commiting sample JSON input file fir aif-config.py
This commit is contained in:
parent
cdc77545ea
commit
094623f710
@ -69,7 +69,7 @@ class aifgen(object):
|
|||||||
'interface entries will be ignored.)\n')
|
'interface entries will be ignored.)\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; ' +
|
||||||
'use \'auto\' for DHCP/DHCPv6): ').format(ifacein), nethelp)
|
'use \'auto\' for DHCP/DHCPv6): ').format(ifacein), nethelp)
|
||||||
if addrin == 'auto':
|
if addrin == 'auto':
|
||||||
addrtype = 'auto'
|
addrtype = 'auto'
|
||||||
@ -79,7 +79,12 @@ class aifgen(object):
|
|||||||
else:
|
else:
|
||||||
addrtype = 'static'
|
addrtype = 'static'
|
||||||
try:
|
try:
|
||||||
ipver = ipaddress.ip_network(ipaddr, strict = False)
|
ipaddress.ip_network(addrin, strict = False)
|
||||||
|
try:
|
||||||
|
ipaddress.IPv4Address(addrin.split('/')[0])
|
||||||
|
ipver = 'ipv4'
|
||||||
|
except ipaddress.AddressValueError:
|
||||||
|
ipver = 'ipv6'
|
||||||
except ValueError:
|
except ValueError:
|
||||||
exit(' !! ERROR: You did not enter a valid IPv4/IPv6 address.')
|
exit(' !! ERROR: You did not enter a valid IPv4/IPv6 address.')
|
||||||
if addrtype == 'static':
|
if addrtype == 'static':
|
||||||
@ -88,7 +93,7 @@ class aifgen(object):
|
|||||||
ipaddress.ip_address(gwin)
|
ipaddress.ip_address(gwin)
|
||||||
except:
|
except:
|
||||||
exit(' !! ERROR: You did not enter a valid IPv4/IPv6 address.')
|
exit(' !! ERROR: You did not enter a valid IPv4/IPv6 address.')
|
||||||
ifaces[ifacein] = {'address': addrin, 'proto': ipver, 'gw': qwin, 'resolvers': []}
|
ifaces[ifacein] = {'address': addrin, 'proto': ipver, 'gw': gwin, 'resolvers': []}
|
||||||
resolversin = chkPrompt('* What DNS resolvers should we use? Can accept a comma-separated list: ', nethelp)
|
resolversin = chkPrompt('* What DNS resolvers should we use? Can accept a comma-separated list: ', nethelp)
|
||||||
for rslv in resolversin.split(','):
|
for rslv in resolversin.split(','):
|
||||||
rslvaddr = rslv.strip()
|
rslvaddr = rslv.strip()
|
||||||
@ -197,10 +202,11 @@ class aifgen(object):
|
|||||||
'\twith a comma). If none, leave this blank: ', mnthelp)
|
'\twith a comma). If none, leave this blank: ', mnthelp)
|
||||||
if mntoptsin == '':
|
if mntoptsin == '':
|
||||||
conf['mounts'][order]['opts'] = False
|
conf['mounts'][order]['opts'] = False
|
||||||
elif not re.match('^[A-Za-z0-9_\.\-]+(,[A-Za-z0-9_\.\-]+)*', mntoptsin):
|
elif not re.match('^[A-Za-z0-9_\.\-=]+(,[A-Za-z0-9_\.\-=]+)*', re.sub('\s', '', mntoptsin)): # TODO: shlex split this instead?
|
||||||
exit(' !! ERROR: You seem to have not specified valid mount options.')
|
exit(' !! ERROR: You seem to have not specified valid mount options.')
|
||||||
else:
|
else:
|
||||||
conf['mounts'][order]['opts'] = mntoptsin
|
# TODO: slex this instead? is it possible for mount opts to contain whitespace?
|
||||||
|
conf['mounts'][order]['opts'] = re.sub('\s', '', mntoptsin)
|
||||||
print('\nNow, let\'s configure the network. Note that at this time, wireless/more exotic networking is not supported by AIF-NG.\n')
|
print('\nNow, let\'s configure the network. Note that at this time, wireless/more exotic networking is not supported by AIF-NG.\n')
|
||||||
conf['network'] = {}
|
conf['network'] = {}
|
||||||
nethelp = ['https://wiki.archlinux.org/index.php/installation_guide#Network_configuration',
|
nethelp = ['https://wiki.archlinux.org/index.php/installation_guide#Network_configuration',
|
||||||
@ -245,19 +251,29 @@ class aifgen(object):
|
|||||||
rebootme = True
|
rebootme = True
|
||||||
else:
|
else:
|
||||||
rebootme = False
|
rebootme = False
|
||||||
conf['system'] = {'timezone': tzin, 'locale': localein, 'chrootpath': chrootpathin, 'kbd': kbdin, 'reboot': rbtin}
|
conf['system'] = {'timezone': tzin, 'locale': localein, 'chrootpath': chrootpathin, 'kbd': kbdin, 'reboot': rebootme}
|
||||||
if self.args['verbose']:
|
if self.args['verbose']:
|
||||||
import pprint
|
import pprint
|
||||||
pprint.pprint(conf)
|
pprint.pprint(conf)
|
||||||
return(conf)
|
return(conf)
|
||||||
|
|
||||||
|
def convertJSON(self):
|
||||||
|
with open(args['inputfile'], 'r') as f:
|
||||||
|
try:
|
||||||
|
conf = json.loads(f.read())
|
||||||
|
except:
|
||||||
|
exit(' !! ERROR: {0} does not seem to be a strict JSON file.'.format(args['inputfile']))
|
||||||
|
return(conf)
|
||||||
|
|
||||||
def validateXML(self):
|
def validateXML(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def main(self):
|
def main(self):
|
||||||
if self.args['oper'] == 'create':
|
if self.args['oper'] == 'create':
|
||||||
conf = self.getOpts()
|
conf = self.getOpts()
|
||||||
if self.args['oper'] in ('create', 'view'):
|
elif self.args['oper'] == 'convert':
|
||||||
|
conf = self.convertJSON()
|
||||||
|
if self.args['oper'] in ('create', 'view', 'convert'):
|
||||||
self.validateXML()
|
self.validateXML()
|
||||||
|
|
||||||
def parseArgs():
|
def parseArgs():
|
||||||
@ -281,12 +297,19 @@ def parseArgs():
|
|||||||
viewargs = subparsers.add_parser('view',
|
viewargs = subparsers.add_parser('view',
|
||||||
help = 'View an AIF-NG XML configuration file.',
|
help = 'View an AIF-NG XML configuration file.',
|
||||||
parents = [commonargs])
|
parents = [commonargs])
|
||||||
|
convertargs = subparsers.add_parser('convert',
|
||||||
|
help = 'Convert a "more" human-readable JSON configuration file to AIF-NG-compatible XML.',
|
||||||
|
parents = [commonargs])
|
||||||
createargs.add_argument('-v',
|
createargs.add_argument('-v',
|
||||||
'--verbose',
|
'--verbose',
|
||||||
dest = 'verbose',
|
dest = 'verbose',
|
||||||
action = 'store_true',
|
action = 'store_true',
|
||||||
help = 'Print the dict of raw values used to create the XML. Mostly/only useful for debugging.')
|
help = 'Print the dict of raw values used to create the XML. Mostly/only useful for debugging.')
|
||||||
|
convertargs.add_argument('-i',
|
||||||
|
'--input',
|
||||||
|
dest = 'inputfile',
|
||||||
|
required = True,
|
||||||
|
help = 'The JSON file to import and convert into XML.')
|
||||||
return(args)
|
return(args)
|
||||||
|
|
||||||
def verifyArgs(args):
|
def verifyArgs(args):
|
||||||
@ -294,27 +317,17 @@ def verifyArgs(args):
|
|||||||
args['cfgfile'] = re.sub('^/+', '/', args['cfgfile'])
|
args['cfgfile'] = re.sub('^/+', '/', args['cfgfile'])
|
||||||
# Path/file handling - make sure we can create the parent dir if it doesn't exist,
|
# 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.
|
# check that we can write to the file, etc.
|
||||||
if args['oper'] == 'create':
|
if args['oper'] in ('create', 'convert'):
|
||||||
args['cfgbak'] = '{0}.bak.{1}'.format(args['cfgfile'], int(datetime.datetime.utcnow().timestamp()))
|
args['cfgbak'] = '{0}.bak.{1}'.format(args['cfgfile'], int(datetime.datetime.utcnow().timestamp()))
|
||||||
try:
|
try:
|
||||||
temp = True
|
temp = True
|
||||||
#mtime = None
|
|
||||||
#atime = None
|
|
||||||
if os.path.lexists(args['cfgfile']):
|
if os.path.lexists(args['cfgfile']):
|
||||||
temp = False
|
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)
|
os.makedirs(os.path.dirname(args['cfgfile']), exist_ok = True)
|
||||||
with open(args['cfgfile'], 'a') as f:
|
with open(args['cfgfile'], 'a') as f:
|
||||||
f.write('')
|
f.write('')
|
||||||
if temp:
|
if temp:
|
||||||
os.remove(args['cfgfile'])
|
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:
|
except OSError as e:
|
||||||
print('\nERROR: {0}: {1}'.format(e.strerror, e.filename))
|
print('\nERROR: {0}: {1}'.format(e.strerror, e.filename))
|
||||||
exit(('\nWe encountered an error when trying to use path {0}.\n' +
|
exit(('\nWe encountered an error when trying to use path {0}.\n' +
|
||||||
@ -327,6 +340,15 @@ def verifyArgs(args):
|
|||||||
print('\nERROR: {0}: {1}'.format(e.strerror, e.filename))
|
print('\nERROR: {0}: {1}'.format(e.strerror, e.filename))
|
||||||
exit(('\nWe encountered an error when trying to use path {0}.\n' +
|
exit(('\nWe encountered an error when trying to use path {0}.\n' +
|
||||||
'Please review the output and address any issues present.').format(args['cfgfile']))
|
'Please review the output and address any issues present.').format(args['cfgfile']))
|
||||||
|
if args['oper'] == 'convert':
|
||||||
|
# And we need to make sure we have read perms to the JSON input file.
|
||||||
|
try:
|
||||||
|
with open(args['inputfile'], '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 read path {0}.\n' +
|
||||||
|
'Please review the output and address any issues present.').format(args['inputfile']))
|
||||||
return(args)
|
return(args)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -334,10 +356,13 @@ def main():
|
|||||||
if not args['oper']:
|
if not args['oper']:
|
||||||
parseArgs().print_help()
|
parseArgs().print_help()
|
||||||
else:
|
else:
|
||||||
# verifyArgs(args)
|
# Once aifgen.main() is complete, we only need to call that.
|
||||||
|
# That should handle all the below logic.
|
||||||
aif = aifgen(verifyArgs(args))
|
aif = aifgen(verifyArgs(args))
|
||||||
if args['oper'] == 'create':
|
if args['oper'] == 'create':
|
||||||
aif.getOpts()
|
aif.getOpts()
|
||||||
|
elif args['oper'] == 'convert':
|
||||||
|
aif.convertJSON()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
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: BUG REPORTS/FEATURE REQUESTS!!!!
|
DOCUMENTATION: aif-config.py (and note sample yaml as well)
|
||||||
|
|
||||||
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
|
||||||
|
97
docs/examples/aif-sample-intermediate.json
Normal file
97
docs/examples/aif-sample-intermediate.json
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
{
|
||||||
|
"disks":
|
||||||
|
{
|
||||||
|
"/dev/sda":
|
||||||
|
{"fmt": "gpt",
|
||||||
|
"parts":
|
||||||
|
{
|
||||||
|
"1":
|
||||||
|
{
|
||||||
|
"start": "0%",
|
||||||
|
"stop": "90%"
|
||||||
|
},
|
||||||
|
"2":
|
||||||
|
{
|
||||||
|
"start": "90%",
|
||||||
|
"stop": "100%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/dev/sdb":
|
||||||
|
{
|
||||||
|
"fmt": "gpt",
|
||||||
|
"parts":
|
||||||
|
{
|
||||||
|
"1":
|
||||||
|
{
|
||||||
|
"start": "0%",
|
||||||
|
"stop": "10%"
|
||||||
|
},
|
||||||
|
"2":
|
||||||
|
{
|
||||||
|
"start": "10%",
|
||||||
|
"stop": "100%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mounts":
|
||||||
|
{
|
||||||
|
"1":
|
||||||
|
{
|
||||||
|
"device": "/dev/sda1",
|
||||||
|
"fstype": "ext4",
|
||||||
|
"opts": "rw,noatime,errors=remount-ro",
|
||||||
|
"target": "/mnt/aif"
|
||||||
|
},
|
||||||
|
"2":
|
||||||
|
{
|
||||||
|
"device": "/dev/sda2",
|
||||||
|
"fstype": "vfat",
|
||||||
|
"opts": "rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro,auto",
|
||||||
|
"target": "/mnt/aif/boot"
|
||||||
|
},
|
||||||
|
"3":
|
||||||
|
{
|
||||||
|
"device": "/dev/sdb1",
|
||||||
|
"fstype": "swap",
|
||||||
|
"opts": false,
|
||||||
|
"target": "swap"},
|
||||||
|
"4":
|
||||||
|
{
|
||||||
|
"device": "/dev/sdb2",
|
||||||
|
"fstype": false,
|
||||||
|
"opts": false,
|
||||||
|
"target": "/mnt/aif/mnt/data"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"network":
|
||||||
|
{
|
||||||
|
"hostname": "aif.loc.lan",
|
||||||
|
"ifaces":
|
||||||
|
{
|
||||||
|
"ens3":
|
||||||
|
{
|
||||||
|
"address": "auto",
|
||||||
|
"gw": false,
|
||||||
|
"proto": "ipv4",
|
||||||
|
"resolvers": false
|
||||||
|
},
|
||||||
|
"ens4":
|
||||||
|
{
|
||||||
|
"address": "192.168.1.2/24",
|
||||||
|
"gw": "192.168.1.1",
|
||||||
|
"proto": "ipv4",
|
||||||
|
"resolvers": ["4.2.2.1", "4.2.2.2", "8.8.8.8"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"system":
|
||||||
|
{
|
||||||
|
"chrootpath": "/mnt/aif",
|
||||||
|
"kbd": "US",
|
||||||
|
"locale": "en_US.UTF-8",
|
||||||
|
"reboot": true,
|
||||||
|
"timezone": "UTC"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user