hoo man. heads up, those password hashes are all just "test"
This commit is contained in:
parent
abaf931f37
commit
4172111fcd
176
aif-config.py
176
aif-config.py
@ -11,6 +11,7 @@ import crypt
|
|||||||
import datetime
|
import datetime
|
||||||
import errno
|
import errno
|
||||||
import ipaddress
|
import ipaddress
|
||||||
|
import json
|
||||||
import getpass
|
import getpass
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@ -176,7 +177,9 @@ class aifgen(object):
|
|||||||
moreIfaces = False
|
moreIfaces = False
|
||||||
return(ifaces)
|
return(ifaces)
|
||||||
def genPassHash(user):
|
def genPassHash(user):
|
||||||
passin = getpass.getpass('* Please enter the password you want to use for {0} (will not echo back): '.format(user))
|
# https://bugs.python.org/issue30360 - keep this disabled until we're ready for primetime.
|
||||||
|
#passin = getpass.getpass('* Please enter the password you want to use for {0} (will not echo back): '.format(user))
|
||||||
|
passin = input('* Please enter the password you want to use for {0}: '.format(user))
|
||||||
if passin not in ('', '!'):
|
if passin not in ('', '!'):
|
||||||
salt = crypt.mksalt(crypt.METHOD_SHA512)
|
salt = crypt.mksalt(crypt.METHOD_SHA512)
|
||||||
salthash = crypt.crypt(passin, salt)
|
salthash = crypt.crypt(passin, salt)
|
||||||
@ -185,15 +188,15 @@ class aifgen(object):
|
|||||||
return(salthash)
|
return(salthash)
|
||||||
def userPrompt(syshelp):
|
def userPrompt(syshelp):
|
||||||
users = {}
|
users = {}
|
||||||
moreUsers = True
|
moreusers = True
|
||||||
while moreUsers:
|
while moreusers:
|
||||||
user = chkPrompt('What username would you like to add? ', syshelp)
|
user = chkPrompt('What username would you like to add? ', syshelp)
|
||||||
if len(user) > 32:
|
if len(user) > 32:
|
||||||
exit(' !! ERROR: Usernames must be less than 32 characters.')
|
exit(' !! ERROR: Usernames must be less than 32 characters.')
|
||||||
if not re.match('^[a-z_][a-z0-9_-]*[$]?$', user):
|
if not re.match('^[a-z_][a-z0-9_-]*[$]?$', user):
|
||||||
exit(' !! ERROR: Your username does not match a valid pattern. See the man page for useradd (\'CAVEATS\').')
|
exit(' !! ERROR: Your username does not match a valid pattern. See the man page for useradd (\'CAVEATS\').')
|
||||||
users[user] = {}
|
users[user] = {}
|
||||||
sudoin = chkPrompt('* Should {0} have (full!) sudo access? (y/{0}n{1}) '.format(user, color.BOLD, color.END), syshelp)
|
sudoin = chkPrompt('* Should {0} have (full!) sudo access? (y/{1}n{2}) '.format(user, color.BOLD, color.END), syshelp)
|
||||||
if re.match('^y(es)?$', sudoin.lower()):
|
if re.match('^y(es)?$', sudoin.lower()):
|
||||||
users[user]['sudo'] = True
|
users[user]['sudo'] = True
|
||||||
else:
|
else:
|
||||||
@ -214,18 +217,24 @@ class aifgen(object):
|
|||||||
'(You\'ll be able to add additional groups in a moment.)\n' +
|
'(You\'ll be able to add additional groups in a moment.)\n' +
|
||||||
'\tThe default, if left blank, is to simply create a group named {0} ' +
|
'\tThe default, if left blank, is to simply create a group named {0} ' +
|
||||||
'(which is what you probably want): ').format(user), syshelp)
|
'(which is what you probably want): ').format(user), syshelp)
|
||||||
if len(grpin) > 32:
|
if grpin != '':
|
||||||
exit(' !! ERROR: Group names must be less than 32 characters.')
|
if len(grpin) > 32:
|
||||||
if not re.match('^[a-z_][a-z0-9_-]*[$]?$', grpin):
|
exit(' !! ERROR: Group names must be less than 32 characters.')
|
||||||
exit(' !! ERROR: Your group name does not match a valid pattern. See the man page for groupadd (\'CAVEATS\').')
|
if not re.match('^[a-z_][a-z0-9_-]*[$]?$', grpin):
|
||||||
users[user]['group'] = grpin
|
exit(' !! ERROR: Your group name does not match a valid pattern. See the man page for groupadd (\'CAVEATS\').')
|
||||||
gidin = chkPrompt(('* What GID should {0} have? Leave this blank if you don\'t care ' +
|
users[user]['group'] = grpin
|
||||||
'(should be fine for most cases): ').format(grpin), syshelp)
|
else:
|
||||||
if gidin != '':
|
users[user]['group'] = False
|
||||||
try:
|
if grpin != '':
|
||||||
users[user]['gid'] = int(gidin)
|
gidin = chkPrompt(('* What GID should {0} have? Leave this blank if you don\'t care ' +
|
||||||
except:
|
'(should be fine for most cases): ').format(grpin), syshelp)
|
||||||
exit(' !! ERROR: The GID must be an integer.')
|
if gidin != '':
|
||||||
|
try:
|
||||||
|
users[user]['gid'] = int(gidin)
|
||||||
|
except:
|
||||||
|
exit(' !! ERROR: The GID must be an integer.')
|
||||||
|
else:
|
||||||
|
users[user]['gid'] = False
|
||||||
else:
|
else:
|
||||||
users[user]['gid'] = False
|
users[user]['gid'] = False
|
||||||
syshelp.append('https://aif.square-r00t.net/#code_home_code')
|
syshelp.append('https://aif.square-r00t.net/#code_home_code')
|
||||||
@ -235,13 +244,13 @@ class aifgen(object):
|
|||||||
if not re.match('^/([^/\x00\s]+(/)?)+)$', homein):
|
if not re.match('^/([^/\x00\s]+(/)?)+)$', homein):
|
||||||
exit('!! ERROR: Path {0} does not seem to be valid.'.format(homein))
|
exit('!! ERROR: Path {0} does not seem to be valid.'.format(homein))
|
||||||
users[user]['home'] = homein
|
users[user]['home'] = homein
|
||||||
|
homecrt = chkPrompt('* Do we need to create {0}? (y/{1}n{2}) '.format(homein, color.BOLD, color.END), syshelp)
|
||||||
|
if re.match('^y(es)?$', homecrt):
|
||||||
|
users[user]['homecreate'] = True
|
||||||
|
else:
|
||||||
|
users[user]['homecreate'] = False
|
||||||
else:
|
else:
|
||||||
users[user]['home'] = False
|
users[user]['home'] = False
|
||||||
homecrt = chkPrompt('* Do we need to create {0}? (y/{1}n{2}) '.format(homein, color.BOLD, color.END), syshelp)
|
|
||||||
if re.match('^y(es)?$', homecrt):
|
|
||||||
users[user]['homecreate'] = True
|
|
||||||
else:
|
|
||||||
users[user]['homecreate'] = False
|
|
||||||
del(syshelp[-1])
|
del(syshelp[-1])
|
||||||
xgrouphelp = 'https://aif.square-r00t.net/#code_xgroup_code'
|
xgrouphelp = 'https://aif.square-r00t.net/#code_xgroup_code'
|
||||||
if xgrouphelp not in syshelp:
|
if xgrouphelp not in syshelp:
|
||||||
@ -254,29 +263,35 @@ class aifgen(object):
|
|||||||
morexgroups = False
|
morexgroups = False
|
||||||
users[user]['xgroups'] = False
|
users[user]['xgroups'] = False
|
||||||
while morexgroups:
|
while morexgroups:
|
||||||
xgrp = chkPrompt('** What is the name of the group you would like to add? ', syshelp)
|
xgrp = chkPrompt('** What is the name of the group you would like to add to {0}? '.format(user), syshelp)
|
||||||
if len(xgrp) > 32:
|
if len(xgrp) > 32:
|
||||||
exit(' !! ERROR: Group names must be less than 32 characters.')
|
exit(' !! ERROR: Group names must be less than 32 characters.')
|
||||||
if not re.match('^[a-z_][a-z0-9_-]*[$]?$', xgrp):
|
if not re.match('^[a-z_][a-z0-9_-]*[$]?$', xgrp):
|
||||||
exit(' !! ERROR: Your group name does not match a valid pattern. See the man page for groupadd (\'CAVEATS\').')
|
exit(' !! ERROR: Your group name does not match a valid pattern. See the man page for groupadd (\'CAVEATS\').')
|
||||||
users[user]['xgroups'][xgrp] = {}
|
users[user]['xgroups'][xgrp] = {}
|
||||||
xgrpcrt = chkPrompt('** Does {0} need to be created? (y/{1}n{2} '.format(xgrp, color.BOLD, color.END), syshelp)
|
xgrpcrt = chkPrompt('** Does the group \'{0}\' need to be created? (y/{1}n{2}) '.format(xgrp, color.BOLD, color.END), syshelp)
|
||||||
if re.match('^y(es)?$', xgrpcrt.lower()):
|
if re.match('^y(es)?$', xgrpcrt.lower()):
|
||||||
users[user]['xgroups'][xgrp]['create'] = True
|
users[user]['xgroups'][xgrp]['create'] = True
|
||||||
|
xgrpgid = chkPrompt(('** What GID should {0} be? If the group will already exist on the new system or ' +
|
||||||
|
'don\'t care,\nleave this blank (should be fine for most cases): ').format(xgrp), syshelp)
|
||||||
|
if xgrpgid != '':
|
||||||
|
try:
|
||||||
|
users[user]['xgroups'][xgrp]['gid'] = int(xgrpgid)
|
||||||
|
except:
|
||||||
|
exit(' !! ERROR: The GID must be an integer.')
|
||||||
|
else:
|
||||||
|
users[user]['xgroups'][xgrp]['gid'] = False
|
||||||
else:
|
else:
|
||||||
users[user]['xgroups'][xgrp]['create'] = False
|
users[user]['xgroups'][xgrp]['create'] = False
|
||||||
xgrpgid = chkPrompt(('** What GID should {0} be? If the group will already exist on the new system or ' +
|
|
||||||
'don\'t care,\nleave this blank (should be fine for most cases): ').format(xgrp), syshelp)
|
|
||||||
if xrpgid != '':
|
|
||||||
try:
|
|
||||||
users[user]['xgroups'][xgrp]['gid'] = int(xgrpid)
|
|
||||||
except:
|
|
||||||
exit(' !! ERROR: The GID must be an integer.')
|
|
||||||
else:
|
|
||||||
users[user]['xgroups'][xgrp]['gid'] = False
|
users[user]['xgroups'][xgrp]['gid'] = False
|
||||||
moreusersin = input('* Would you like to add additional extra groups for {0}? (y/{1}n{2}) '.format(user, color.BOLD, color.END))
|
morexgrpsin = input('* Would you like to add additional extra groups for {0}? (y/{1}n{2}) '.format(user,
|
||||||
if not re.match('^y(es)?$', moreusersin.lower()):
|
color.BOLD,
|
||||||
|
color.END))
|
||||||
|
if not re.match('^y(es)?$', morexgrpsin.lower()):
|
||||||
morexgroups = False
|
morexgroups = False
|
||||||
|
moreusersin = chkPrompt('* Would you like to add additional users? (y/{0}n{1}) '.format(color.BOLD, color.END), syshelp)
|
||||||
|
if not re.match('^y(es)?$', moreusersin.lower()):
|
||||||
|
moreusers = False
|
||||||
return(users)
|
return(users)
|
||||||
def svcsPrompt(svchelp):
|
def svcsPrompt(svchelp):
|
||||||
svcs = {}
|
svcs = {}
|
||||||
@ -289,7 +304,7 @@ class aifgen(object):
|
|||||||
if re.match('^no?$', svcstatusin.lower()):
|
if re.match('^no?$', svcstatusin.lower()):
|
||||||
svcs[svc] = False
|
svcs[svc] = False
|
||||||
else:
|
else:
|
||||||
svcs[svc] - True
|
svcs[svc] = True
|
||||||
moreservices = input('* Would you like to manage another service? (y/{0}n{1}) '.format(color.BOLD, color.END))
|
moreservices = input('* Would you like to manage another service? (y/{0}n{1}) '.format(color.BOLD, color.END))
|
||||||
if not re.match('^y(es)?$', moreservices.lower()):
|
if not re.match('^y(es)?$', moreservices.lower()):
|
||||||
moresvcs = False
|
moresvcs = False
|
||||||
@ -474,10 +489,10 @@ class aifgen(object):
|
|||||||
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('You may reply with \'wikihelp\' on the first prompt of a question for the relevant link(s) in the Arch wiki ' +
|
||||||
'(and other resources).\n')
|
'(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']
|
||||||
diskin = chkPrompt('\nWhat disk(s) would you like to be configured on the target system?\n' +
|
diskin = chkPrompt('\n* 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'}
|
||||||
@ -487,8 +502,8 @@ class aifgen(object):
|
|||||||
if not re.match('^/dev/[A-Za-z0]+', disk):
|
if not re.match('^/dev/[A-Za-z0]+', disk):
|
||||||
exit('!! ERROR: Disk {0} does not seem to be a valid device path.'.format(disk))
|
exit('!! ERROR: Disk {0} does not seem to be a valid device path.'.format(disk))
|
||||||
conf['disks'][disk] = {}
|
conf['disks'][disk] = {}
|
||||||
print('\nConfiguring disk {0} ...'.format(disk))
|
print('\n* Configuring disk {0} ...'.format(disk))
|
||||||
fmtin = chkPrompt('* What format should this disk use (gpt/bios)? ', diskhelp)
|
fmtin = chkPrompt('** What format should this disk use (gpt/bios)? ', diskhelp)
|
||||||
fmt = fmtin.lower()
|
fmt = fmtin.lower()
|
||||||
if fmt not in ('gpt', 'bios'):
|
if fmt not in ('gpt', 'bios'):
|
||||||
exit(' !! ERROR: Must be one of \'gpt\' or \'bios\'.')
|
exit(' !! ERROR: Must be one of \'gpt\' or \'bios\'.')
|
||||||
@ -498,7 +513,7 @@ class aifgen(object):
|
|||||||
maxpart = '256'
|
maxpart = '256'
|
||||||
else:
|
else:
|
||||||
maxpart = '4' # yeah, extended volumes can do more, but that's not supported in AIF-NG. yet?
|
maxpart = '4' # yeah, extended volumes can do more, but that's not supported in AIF-NG. yet?
|
||||||
partnumsin = chkPrompt('* How many partitions should this disk have? (Maximum: {0}) '.format(maxpart), diskhelp)
|
partnumsin = chkPrompt('** How many partitions should this disk have? (Maximum: {0}) '.format(maxpart), diskhelp)
|
||||||
try:
|
try:
|
||||||
int(partnumsin)
|
int(partnumsin)
|
||||||
except:
|
except:
|
||||||
@ -525,10 +540,10 @@ class aifgen(object):
|
|||||||
if fstypein not in fstypes.keys():
|
if fstypein not in fstypes.keys():
|
||||||
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('\tSelected {0}'.format(fstypes[fstypein]))
|
print('\t(Selected {0})'.format(fstypes[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']
|
||||||
mntin = chkPrompt('\nWhat mountpoint(s) would you like to be configured on the target system?\n' +
|
mntin = chkPrompt('\n* 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'] = {}
|
||||||
@ -536,11 +551,11 @@ 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('\nConfiguring mountpoint {0} ...'.format(mount))
|
print('\n* Configuring mountpoint {0} ...'.format(mount))
|
||||||
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.')
|
||||||
ordrin = chkPrompt('* What order should this mount occur in relation to others?\n\t'+
|
ordrin = chkPrompt('** What order should this mount occur in relation to others?\n\t'+
|
||||||
'Must be a unique integer (lower numbers mount before higher numbers): ', mnthelp)
|
'Must be a unique integer (lower numbers mount before higher numbers): ', mnthelp)
|
||||||
try:
|
try:
|
||||||
order = int(ordrin)
|
order = int(ordrin)
|
||||||
@ -551,30 +566,35 @@ class aifgen(object):
|
|||||||
conf['mounts'][order] = {}
|
conf['mounts'][order] = {}
|
||||||
conf['mounts'][order]['target'] = mount
|
conf['mounts'][order]['target'] = mount
|
||||||
conf['mounts'][order]['device'] = dvcin
|
conf['mounts'][order]['device'] = dvcin
|
||||||
fstypein = chkPrompt('* What filesystem type should this be mounted as (i.e. mount\'s -t option)? This is optional,\n\t' +
|
if mount != 'swap':
|
||||||
'but may be required for more exotic filesystem types. If you don\'t have to specify one,\n\t' +
|
fstypein = chkPrompt('** What filesystem type should this be mounted as (i.e. mount\'s -t option)? This is optional,\n\t' +
|
||||||
'just leave this blank: ', mnthelp)
|
'but may be required for more exotic filesystem types. If you don\'t have to specify one,\n\t' +
|
||||||
if fstypein == '':
|
'just leave this blank: ', mnthelp)
|
||||||
|
if fstypein == '':
|
||||||
|
conf['mounts'][order]['fstype'] = False
|
||||||
|
elif not re.match('^[a-z]+([0-9]+)?$', fstypein): # Not 100%, but should catch most faulty entries
|
||||||
|
exit(' !! ERROR: {0} does not seem to be a valid filesystem type.'.format(fstypein))
|
||||||
|
else:
|
||||||
|
conf['mounts'][order]['fstype'] = fstypein
|
||||||
|
mntoptsin = chkPrompt('** What, if any, mount option(s) (mount\'s -o option) do you require? (Multiple options should be separated\n' +
|
||||||
|
'\twith a comma). If none, leave this blank: ', mnthelp)
|
||||||
|
if mntoptsin == '':
|
||||||
|
conf['mounts'][order]['opts'] = False
|
||||||
|
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.')
|
||||||
|
else:
|
||||||
|
# TODO: slex this instead? is it possible for mount opts to contain whitespace?
|
||||||
|
conf['mounts'][order]['opts'] = re.sub('\s', '', mntoptsin)
|
||||||
|
else:
|
||||||
conf['mounts'][order]['fstype'] = False
|
conf['mounts'][order]['fstype'] = False
|
||||||
elif not re.match('^[a-z]+([0-9]+)?$', fstypein): # Not 100%, but should catch most faulty entries
|
|
||||||
exit(' !! ERROR: {0} does not seem to be a valid filesystem type.'.format(fstypein))
|
|
||||||
else:
|
|
||||||
conf['mounts'][order]['fstype'] = fstypein
|
|
||||||
mntoptsin = chkPrompt('* What, if any, mount option(s) (mount\'s -o option) do you require? (Multiple options should be separated\n' +
|
|
||||||
'\twith a comma). If none, leave this blank: ', mnthelp)
|
|
||||||
if mntoptsin == '':
|
|
||||||
conf['mounts'][order]['opts'] = False
|
conf['mounts'][order]['opts'] = False
|
||||||
elif not re.match('^[A-Za-z0-9_\.\-=]+(,[A-Za-z0-9_\.\-=]+)*', re.sub('\s', '', mntoptsin)): # TODO: shlex split this instead?
|
print('\nNow, let\'s configure the network. Note that at this time,' +
|
||||||
exit(' !! ERROR: You seem to have not specified valid mount options.')
|
'\twireless/more exotic networking is not supported by AIF-NG.\n')
|
||||||
else:
|
|
||||||
# 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')
|
|
||||||
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',
|
||||||
'https://aif.square-r00t.net/#code_network_code']
|
'https://aif.square-r00t.net/#code_network_code']
|
||||||
hostnamein = chkPrompt('What should the newly-installed system\'s hostname be?\n\t' +
|
hostnamein = chkPrompt('* What should the newly-installed system\'s hostname be?\n' +
|
||||||
'It must be in FQDN format, but can be a non-existent domain: ', nethelp)
|
'\tIt must be in FQDN format, but can be a non-existent domain: ', nethelp)
|
||||||
hostname = hostnamein.lower()
|
hostname = hostnamein.lower()
|
||||||
if len(hostname) > 253:
|
if len(hostname) > 253:
|
||||||
exit(' !! ERROR: A FQDN cannot be more than 253 characters (RFC 1035, 2.3.4)')
|
exit(' !! ERROR: A FQDN cannot be more than 253 characters (RFC 1035, 2.3.4)')
|
||||||
@ -614,12 +634,12 @@ class aifgen(object):
|
|||||||
else:
|
else:
|
||||||
rebootme = False
|
rebootme = False
|
||||||
conf['system'] = {'timezone': tzin, 'locale': localein, 'chrootpath': chrootpathin, 'kbd': kbdin, 'reboot': rebootme}
|
conf['system'] = {'timezone': tzin, 'locale': localein, 'chrootpath': chrootpathin, 'kbd': kbdin, 'reboot': rebootme}
|
||||||
syshelp[1] = 'https://aif.square-r00t.net/#code_users_code'
|
syshelp.append('https://aif.square-r00t.net/#code_users_code')
|
||||||
print('\nNow let\'s handle some user accounts. For passwords, you can either enter the password you want to use,\n' +
|
print('\nNow let\'s handle some user accounts. For passwords, you can either enter the password you want to use,\n' +
|
||||||
'a \'!\' (in which case TTY login will be disabled but e.g. SSH will still work), or just hit enter to leave it blank\n' +
|
'a \'!\' (in which case TTY login will be disabled but e.g. SSH will still work), or just hit enter to leave it blank\n' +
|
||||||
'(which is HIGHLY not recommended - it means anyone can login by just pressing enter at the login!)\n')
|
'(which is HIGHLY not recommended - it means anyone can login by just pressing enter at the login!)\n')
|
||||||
print('Let\'s configure the root user.')
|
print('Let\'s configure the root user.')
|
||||||
conf['system']['rootpass'] = genPassHash(root)
|
conf['system']['rootpass'] = genPassHash('root')
|
||||||
moreusers = input('Would you like to add one or more regular user(s)? (y/{0}n{1}) '.format(color.BOLD, color.END))
|
moreusers = input('Would you like to add one or more regular user(s)? (y/{0}n{1}) '.format(color.BOLD, color.END))
|
||||||
if re.match('^y(es)?$', moreusers.lower()):
|
if re.match('^y(es)?$', moreusers.lower()):
|
||||||
syshelp.append('https://aif.square-r00t.net/#code_user_code')
|
syshelp.append('https://aif.square-r00t.net/#code_user_code')
|
||||||
@ -662,7 +682,9 @@ class aifgen(object):
|
|||||||
'https://aif.square-r00t.net/#code_bootloader_code']
|
'https://aif.square-r00t.net/#code_bootloader_code']
|
||||||
conf['boot'] = {}
|
conf['boot'] = {}
|
||||||
btldrin = chkPrompt('* Almost done! Please choose a bootloader. ({0}grub{1}/systemd) '.format(color.BOLD, color.END), btldrhelp)
|
btldrin = chkPrompt('* Almost done! Please choose a bootloader. ({0}grub{1}/systemd) '.format(color.BOLD, color.END), btldrhelp)
|
||||||
if not re.match('^(grub|systemd)$', btldrin.lower()):
|
if btldrin == '':
|
||||||
|
btldrin = 'grub'
|
||||||
|
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:
|
else:
|
||||||
conf['boot']['bootloader'] = btldrin.lower()
|
conf['boot']['bootloader'] = btldrin.lower()
|
||||||
@ -676,7 +698,7 @@ class aifgen(object):
|
|||||||
conf['boot']['efi'] = True
|
conf['boot']['efi'] = True
|
||||||
bttgtstr = 'ESP (EFI System Partition)'
|
bttgtstr = 'ESP (EFI System Partition)'
|
||||||
btrgx = re.compile('^/([^/\x00\s]+(/)?)+$')
|
btrgx = re.compile('^/([^/\x00\s]+(/)?)+$')
|
||||||
bttgtin = chkPrompt('** What is the target for {0}? That is, the path to the {1}: '.format(btldrin.lower(), bttgtstr), btldrhelp)
|
bttgtin = chkPrompt('** What is the target for {0}? That is, the path to the {1} (within the chroot): '.format(btldrin.lower(), bttgtstr), btldrhelp)
|
||||||
if not btrgx.match(bttgtin):
|
if not btrgx.match(bttgtin):
|
||||||
exit(' !! ERROR: That doesn\'t seem to be a valid {0}.'.format(bttgtstr))
|
exit(' !! ERROR: That doesn\'t seem to be a valid {0}.'.format(bttgtstr))
|
||||||
else:
|
else:
|
||||||
@ -692,12 +714,14 @@ class aifgen(object):
|
|||||||
if self.args['verbose']:
|
if self.args['verbose']:
|
||||||
import pprint
|
import pprint
|
||||||
pprint.pprint(conf)
|
pprint.pprint(conf)
|
||||||
|
if self.args['verbose_raw']:
|
||||||
|
print(conf)
|
||||||
return(conf)
|
return(conf)
|
||||||
|
|
||||||
def convertJSON(self):
|
def convertJSON(self):
|
||||||
with open(args['inputfile'], 'r') as f:
|
with open(self.args['inputfile'], 'r') as f:
|
||||||
try:
|
try:
|
||||||
conf = json.loads(f.read())
|
conf = json.load(f)
|
||||||
except:
|
except:
|
||||||
exit(' !! ERROR: {0} does not seem to be a strict JSON file.'.format(args['inputfile']))
|
exit(' !! ERROR: {0} does not seem to be a strict JSON file.'.format(args['inputfile']))
|
||||||
return(conf)
|
return(conf)
|
||||||
@ -723,7 +747,7 @@ class aifgen(object):
|
|||||||
conf = self.getOpts()
|
conf = self.getOpts()
|
||||||
elif self.args['oper'] == 'convert':
|
elif self.args['oper'] == 'convert':
|
||||||
conf = self.convertJSON()
|
conf = self.convertJSON()
|
||||||
if self.args['oper'] in ('create', 'convert'):
|
if self.args['oper'] in ('create', 'convert', 'validate'):
|
||||||
self.validateXML()
|
self.validateXML()
|
||||||
|
|
||||||
def parseArgs():
|
def parseArgs():
|
||||||
@ -752,6 +776,11 @@ def parseArgs():
|
|||||||
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.')
|
||||||
|
createargs.add_argument('-v:r',
|
||||||
|
'--verbose-raw',
|
||||||
|
dest = 'verbose_raw',
|
||||||
|
action = 'store_true',
|
||||||
|
help = 'Like -v, but prints the unformatted dict.')
|
||||||
convertargs.add_argument('-i',
|
convertargs.add_argument('-i',
|
||||||
'--input',
|
'--input',
|
||||||
dest = 'inputfile',
|
dest = 'inputfile',
|
||||||
@ -798,12 +827,7 @@ def main():
|
|||||||
# Once aifgen.main() is complete, we only need to call that.
|
# Once aifgen.main() is complete, we only need to call that.
|
||||||
# That should handle all the below logic.
|
# That should handle all the below logic.
|
||||||
aif = aifgen(verifyArgs(args))
|
aif = aifgen(verifyArgs(args))
|
||||||
if args['oper'] == 'create':
|
aif.main()
|
||||||
aif.getOpts()
|
|
||||||
if args['oper'] == 'validate':
|
|
||||||
aif.validateXML()
|
|
||||||
elif args['oper'] == 'convert':
|
|
||||||
aif.convertJSON()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
@ -1,97 +1,156 @@
|
|||||||
{
|
{
|
||||||
"disks":
|
"boot": {
|
||||||
{
|
"efi": true,
|
||||||
"/dev/sda":
|
"target": "/boot"
|
||||||
{"fmt": "gpt",
|
},
|
||||||
"parts":
|
"disks": {
|
||||||
{
|
"/dev/sda": {
|
||||||
"1":
|
"fmt": "gpt",
|
||||||
{
|
"parts": {
|
||||||
"start": "0%",
|
"1": {
|
||||||
"stop": "90%"
|
"start": "0%",
|
||||||
},
|
"stop": "95%"
|
||||||
"2":
|
},
|
||||||
{
|
"2": {
|
||||||
"start": "90%",
|
"start": "95%",
|
||||||
"stop": "100%"
|
"stop": "100%"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/dev/sdb":
|
"/dev/sdb": {
|
||||||
{
|
"fmt": "gpt",
|
||||||
"fmt": "gpt",
|
"parts": {
|
||||||
"parts":
|
"1": {
|
||||||
{
|
"start": "0%",
|
||||||
"1":
|
"stop": "47%"
|
||||||
{
|
},
|
||||||
"start": "0%",
|
"2": {
|
||||||
"stop": "10%"
|
"start": "47%",
|
||||||
},
|
"stop": "95%"
|
||||||
"2":
|
},
|
||||||
{
|
"3": {
|
||||||
"start": "10%",
|
"start": "95%",
|
||||||
"stop": "100%"
|
"stop": "100%"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mounts":
|
"mounts": {
|
||||||
{
|
"1": {
|
||||||
"1":
|
"device": "/dev/sda1",
|
||||||
{
|
"fstype": "ext4",
|
||||||
"device": "/dev/sda1",
|
"opts": "defaults",
|
||||||
"fstype": "ext4",
|
"target": "/mnt/aif"
|
||||||
"opts": "rw,noatime,errors=remount-ro",
|
},
|
||||||
"target": "/mnt/aif"
|
"2": {
|
||||||
},
|
"device": "/dev/sda2",
|
||||||
"2":
|
"fstype": "vfat",
|
||||||
{
|
"opts": "rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro",
|
||||||
"device": "/dev/sda2",
|
"target": "/mnt/aif/boot"
|
||||||
"fstype": "vfat",
|
},
|
||||||
"opts": "rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro,auto",
|
"3": {
|
||||||
"target": "/mnt/aif/boot"
|
"device": "/dev/sdb1",
|
||||||
},
|
"fstype": "ext4",
|
||||||
"3":
|
"opts": "defaults",
|
||||||
{
|
"target": "/mnt/aif/home"
|
||||||
"device": "/dev/sdb1",
|
},
|
||||||
"fstype": "swap",
|
"4": {
|
||||||
"opts": false,
|
"device": "/dev/sdb2",
|
||||||
"target": "swap"},
|
"fstype": "ext4",
|
||||||
"4":
|
"opts": "defaults",
|
||||||
{
|
"target": "/mnt/aif/mnt/data"
|
||||||
"device": "/dev/sdb2",
|
},
|
||||||
"fstype": false,
|
"5": {
|
||||||
"opts": false,
|
"device": "/dev/sdb3",
|
||||||
"target": "/mnt/aif/mnt/data"
|
"fstype": false,
|
||||||
}
|
"opts": false,
|
||||||
},
|
"target": "swap"
|
||||||
"network":
|
}
|
||||||
{
|
},
|
||||||
"hostname": "aif.loc.lan",
|
"network": {
|
||||||
"ifaces":
|
"hostname": "aif.loc.lan",
|
||||||
{
|
"ifaces": {
|
||||||
"ens3":
|
"ens3": {
|
||||||
{
|
"address": "auto",
|
||||||
"address": "auto",
|
"gw": false,
|
||||||
"gw": false,
|
"proto": "ipv4",
|
||||||
"proto": "ipv4",
|
"resolvers": false
|
||||||
"resolvers": false
|
},
|
||||||
},
|
"ens4": {
|
||||||
"ens4":
|
"address": "192.168.1.2/24",
|
||||||
{
|
"gw": "192.168.1.1",
|
||||||
"address": "192.168.1.2/24",
|
"proto": "ipv4",
|
||||||
"gw": "192.168.1.1",
|
"resolvers": [
|
||||||
"proto": "ipv4",
|
"4.2.2.1",
|
||||||
"resolvers": ["4.2.2.1", "4.2.2.2", "8.8.8.8"]
|
"4.2.2.2"
|
||||||
}
|
]
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"system":
|
},
|
||||||
{
|
"software": {
|
||||||
"chrootpath": "/mnt/aif",
|
"packages": {
|
||||||
"kbd": "US",
|
"openssh": "None"
|
||||||
"locale": "en_US.UTF-8",
|
},
|
||||||
"reboot": true,
|
"pkgr": false,
|
||||||
"timezone": "UTC"
|
"repos": {
|
||||||
}
|
"community": {
|
||||||
|
"enabled": true,
|
||||||
|
"mirror": "file:///etc/pacman.d/mirrorlist",
|
||||||
|
"siglevel": "default"
|
||||||
|
},
|
||||||
|
"community-testing": {
|
||||||
|
"enabled": false,
|
||||||
|
"mirror": "file:///etc/pacman.d/mirrorlist",
|
||||||
|
"siglevel": "default"
|
||||||
|
},
|
||||||
|
"core": {
|
||||||
|
"enabled": true,
|
||||||
|
"mirror": "file:///etc/pacman.d/mirrorlist",
|
||||||
|
"siglevel": "default"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"enabled": true,
|
||||||
|
"mirror": "file:///etc/pacman.d/mirrorlist",
|
||||||
|
"siglevel": "default"
|
||||||
|
},
|
||||||
|
"multilib": {
|
||||||
|
"enabled": true,
|
||||||
|
"mirror": "file:///etc/pacman.d/mirrorlist",
|
||||||
|
"siglevel": "default"
|
||||||
|
},
|
||||||
|
"multilib-testing": {
|
||||||
|
"enabled": false,
|
||||||
|
"mirror": "file:///etc/pacman.d/mirrorlist",
|
||||||
|
"siglevel": "default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"system": {
|
||||||
|
"chrootpath": "/mnt/aif",
|
||||||
|
"kbd": "US",
|
||||||
|
"locale": "en_US.UTF-8",
|
||||||
|
"reboot": true,
|
||||||
|
"rootpass": "$6$0jk/xhwahQHTi5QP$VWTgGlHNdSBDbQmJXUwJPZqajfL3JqYYF7Ghxk3ZSKi12WWXb49KsjR7q0bigvgBBBk5A/mvYES3/qareytFS0",
|
||||||
|
"services": {
|
||||||
|
"sshd": true
|
||||||
|
},
|
||||||
|
"timezone": "UTC",
|
||||||
|
"users": {
|
||||||
|
"aifusr": {
|
||||||
|
"comment": "A Test User",
|
||||||
|
"gid": false,
|
||||||
|
"group": false,
|
||||||
|
"home": false,
|
||||||
|
"password": "$6$IlEwDkNmZRuTrT97$vKHjREGspspApBd8aQ/y1S43yRmGMjAzqOmdjNRLWaZyNKqGPrIjMHV9CJc7BzQgU12pRz3cwC6yyc8BDFARu/",
|
||||||
|
"sudo": true,
|
||||||
|
"uid": false,
|
||||||
|
"xgroups": {
|
||||||
|
"users": {
|
||||||
|
"create": false,
|
||||||
|
"gid": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
73
docs/examples/aif-sample-intermediate.json.txt
Normal file
73
docs/examples/aif-sample-intermediate.json.txt
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{'boot': {'efi': True, 'target': '/boot'},
|
||||||
|
'disks': {'/dev/sda': {'fmt': 'gpt',
|
||||||
|
'parts': {1: {'start': '0%', 'stop': '95%'},
|
||||||
|
2: {'start': '95%', 'stop': '100%'}}},
|
||||||
|
'/dev/sdb': {'fmt': 'gpt',
|
||||||
|
'parts': {1: {'start': '0%', 'stop': '47%'},
|
||||||
|
2: {'start': '47%', 'stop': '95%'},
|
||||||
|
3: {'start': '95%', 'stop': '100%'}}}},
|
||||||
|
'mounts': {1: {'device': '/dev/sda1',
|
||||||
|
'fstype': 'ext4',
|
||||||
|
'opts': 'defaults',
|
||||||
|
'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',
|
||||||
|
'target': '/mnt/aif/boot'},
|
||||||
|
3: {'device': '/dev/sdb1',
|
||||||
|
'fstype': 'ext4',
|
||||||
|
'opts': 'defaults',
|
||||||
|
'target': '/mnt/aif/home'},
|
||||||
|
4: {'device': '/dev/sdb2',
|
||||||
|
'fstype': 'ext4',
|
||||||
|
'opts': 'defaults',
|
||||||
|
'target': '/mnt/aif/mnt/data'},
|
||||||
|
5: {'device': '/dev/sdb3',
|
||||||
|
'fstype': False,
|
||||||
|
'opts': False,
|
||||||
|
'target': 'swap'}},
|
||||||
|
'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']}}},
|
||||||
|
'software': {'packages': {'openssh': 'None'},
|
||||||
|
'pkgr': False,
|
||||||
|
'repos': {'community': {'enabled': True,
|
||||||
|
'mirror': 'file:///etc/pacman.d/mirrorlist',
|
||||||
|
'siglevel': 'default'},
|
||||||
|
'community-testing': {'enabled': False,
|
||||||
|
'mirror': 'file:///etc/pacman.d/mirrorlist',
|
||||||
|
'siglevel': 'default'},
|
||||||
|
'core': {'enabled': True,
|
||||||
|
'mirror': 'file:///etc/pacman.d/mirrorlist',
|
||||||
|
'siglevel': 'default'},
|
||||||
|
'extra': {'enabled': True,
|
||||||
|
'mirror': 'file:///etc/pacman.d/mirrorlist',
|
||||||
|
'siglevel': 'default'},
|
||||||
|
'multilib': {'enabled': True,
|
||||||
|
'mirror': 'file:///etc/pacman.d/mirrorlist',
|
||||||
|
'siglevel': 'default'},
|
||||||
|
'multilib-testing': {'enabled': False,
|
||||||
|
'mirror': 'file:///etc/pacman.d/mirrorlist',
|
||||||
|
'siglevel': 'default'}}},
|
||||||
|
'system': {'chrootpath': '/mnt/aif',
|
||||||
|
'kbd': 'US',
|
||||||
|
'locale': 'en_US.UTF-8',
|
||||||
|
'reboot': True,
|
||||||
|
'rootpass': '$6$0jk/xhwahQHTi5QP$VWTgGlHNdSBDbQmJXUwJPZqajfL3JqYYF7Ghxk3ZSKi12WWXb49KsjR7q0bigvgBBBk5A/mvYES3/qareytFS0',
|
||||||
|
'services': {'sshd': True},
|
||||||
|
'timezone': 'UTC',
|
||||||
|
'users': {'aifusr': {'comment': 'A Test User',
|
||||||
|
'gid': False,
|
||||||
|
'group': False,
|
||||||
|
'home': False,
|
||||||
|
'password': '$6$IlEwDkNmZRuTrT97$vKHjREGspspApBd8aQ/y1S43yRmGMjAzqOmdjNRLWaZyNKqGPrIjMHV9CJc7BzQgU12pRz3cwC6yyc8BDFARu/',
|
||||||
|
'sudo': True,
|
||||||
|
'uid': False,
|
||||||
|
'xgroups': {'users': {'create': False,
|
||||||
|
'gid': False}}}}}}
|
167
extras/createtest.expect
Executable file
167
extras/createtest.expect
Executable file
@ -0,0 +1,167 @@
|
|||||||
|
#!/usr/bin/expect -f
|
||||||
|
|
||||||
|
log_file -noappend /tmp/expect.log
|
||||||
|
set force_conservative 0 ;# set to 1 to force conservative mode even if
|
||||||
|
;# script wasn't run conservatively originally
|
||||||
|
if {$force_conservative} {
|
||||||
|
set send_slow {1 .1}
|
||||||
|
proc send {ignore arg} {
|
||||||
|
sleep .1
|
||||||
|
exp_send -s -- $arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set send_slow {10 .001}
|
||||||
|
|
||||||
|
set timeout -1
|
||||||
|
spawn ./aif-config.py create -v:r -f /tmp/aif.xml
|
||||||
|
## disks
|
||||||
|
send -- "/dev/sda,/dev/sdb\r"
|
||||||
|
# sda
|
||||||
|
send -- "gpt\r"
|
||||||
|
send -- "2\r"
|
||||||
|
# sda1
|
||||||
|
send -- "0%\r"
|
||||||
|
send -- "95%\r"
|
||||||
|
send -- "8300\r"
|
||||||
|
# sda2
|
||||||
|
send -- "95%\r"
|
||||||
|
send -- "100%\r"
|
||||||
|
send -- "ef00\r"
|
||||||
|
# sdb
|
||||||
|
send -- "gpt\r"
|
||||||
|
send -- "3\r"
|
||||||
|
# sdb1
|
||||||
|
send -- "0%\r"
|
||||||
|
send -- "47%\r"
|
||||||
|
send -- "8300\r"
|
||||||
|
# sdb2
|
||||||
|
send -- "47%\r"
|
||||||
|
send -- "95%\r"
|
||||||
|
send -- "8300\r"
|
||||||
|
# sdb3
|
||||||
|
send -- "95%\r"
|
||||||
|
send -- "100%\r"
|
||||||
|
send -- "8200\r"
|
||||||
|
## mounts
|
||||||
|
send -- "/mnt/aif,/mnt/aif/boot,/mnt/aif/home,/mnt/aif/mnt/data,swap\r"
|
||||||
|
# /mnt/aif
|
||||||
|
send -- "/dev/sda1\r"
|
||||||
|
send -- "1\r"
|
||||||
|
send -- "ext4\r"
|
||||||
|
send -- "defaults\r"
|
||||||
|
# /mnt/aif/boot
|
||||||
|
send -- "/dev/sda2\r"
|
||||||
|
send -- "2\r"
|
||||||
|
send -- "vfat\r"
|
||||||
|
send -- "rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro\r"
|
||||||
|
# /mnt/aif/home
|
||||||
|
send -- "/dev/sdb1\r"
|
||||||
|
send -- "3\r"
|
||||||
|
send -- "ext4\r"
|
||||||
|
send -- "defaults\r"
|
||||||
|
# /mnt/aif/mnt/data
|
||||||
|
send -- "/dev/sdb2\r"
|
||||||
|
send -- "4\r"
|
||||||
|
send -- "ext4\r"
|
||||||
|
send -- "defaults\r"
|
||||||
|
# swap
|
||||||
|
send -- "/dev/sdb3\r"
|
||||||
|
send -- "5\r"
|
||||||
|
## network
|
||||||
|
# hostname
|
||||||
|
send -- "aif.loc.lan\r"
|
||||||
|
# interface
|
||||||
|
send -- "ens3\r"
|
||||||
|
send -- "auto\r"
|
||||||
|
send -- "ipv4\r"
|
||||||
|
# add another interface?
|
||||||
|
send -- "y\r"
|
||||||
|
# second interface
|
||||||
|
send -- "ens4\r"
|
||||||
|
send -- "192.168.1.2/24\r"
|
||||||
|
send -- "192.168.1.1\r"
|
||||||
|
send -- "4.2.2.1,4.2.2.2\r"
|
||||||
|
# add another interface? default is no
|
||||||
|
send -- "\r"
|
||||||
|
## system
|
||||||
|
# timezone (default is UTC)
|
||||||
|
send -- "\r"
|
||||||
|
# locale (default is en_US.UTF-8
|
||||||
|
send -- "\r"
|
||||||
|
# chroot path
|
||||||
|
send -- "/mnt/aif\r"
|
||||||
|
# kbd (default is US)
|
||||||
|
send -- "\r"
|
||||||
|
# reboot host after install? default is yes
|
||||||
|
send -- "\r"
|
||||||
|
# root password
|
||||||
|
send -- "test\r"
|
||||||
|
# add user?
|
||||||
|
send -- "y\r"
|
||||||
|
# user
|
||||||
|
send -- "aifusr\r"
|
||||||
|
# sudo access
|
||||||
|
send -- "y\r"
|
||||||
|
# password
|
||||||
|
send -- "test\r"
|
||||||
|
send -- "A Test User\r"
|
||||||
|
# uid (default is autogen)
|
||||||
|
send -- "\r"
|
||||||
|
# primary group (default is autogen'd based on username)
|
||||||
|
send -- "\r"
|
||||||
|
# home dir (default is e.g. /home/username)
|
||||||
|
send -- "\r"
|
||||||
|
# add exta groups?
|
||||||
|
send -- "y\r"
|
||||||
|
# extra group
|
||||||
|
send -- "users\r"
|
||||||
|
# need to be created? default is no
|
||||||
|
send -- "\r"
|
||||||
|
# add another extra group? default is no
|
||||||
|
send -- "\r"
|
||||||
|
# add more users? default is no
|
||||||
|
send -- "\r"
|
||||||
|
# enable/disable services
|
||||||
|
send -- "y\r"
|
||||||
|
# service
|
||||||
|
send -- "sshd\r"
|
||||||
|
# enable? default is yes
|
||||||
|
send -- "\r"
|
||||||
|
# manage another service? default is no
|
||||||
|
send -- "\r"
|
||||||
|
# packager (default is pacman)
|
||||||
|
send -- "\r"
|
||||||
|
# review default repos? default is yes
|
||||||
|
send -- "\r"
|
||||||
|
# edit any of them?
|
||||||
|
send -- "y\r"
|
||||||
|
# edit the 6th repo (multilib)
|
||||||
|
send -- "6\r"
|
||||||
|
# enabled?
|
||||||
|
send -- "y\r"
|
||||||
|
# siglevel (default is unchanged)
|
||||||
|
send -- "\r"
|
||||||
|
# mirror URI (default is unchanged)
|
||||||
|
send -- "\r"
|
||||||
|
# edit another repo? default is no
|
||||||
|
send -- "\r"
|
||||||
|
# add additional repositories? default is no
|
||||||
|
send -- "\r"
|
||||||
|
# install extra software?
|
||||||
|
send -- "y\r"
|
||||||
|
# software
|
||||||
|
send -- "openssh\r"
|
||||||
|
# repository (optional)
|
||||||
|
send -- "\r"
|
||||||
|
# add another package?
|
||||||
|
send -- "\r"
|
||||||
|
# bootloader (default is grub)
|
||||||
|
send -- "\r"
|
||||||
|
# system supports UEFI? default is yes
|
||||||
|
send -- "\r"
|
||||||
|
# ESP/EFI system partition
|
||||||
|
send -- "/boot\r"
|
||||||
|
# any hook scripts? default is no
|
||||||
|
send -- "\r"
|
||||||
|
expect eof
|
49
extras/txttojson.py
Executable file
49
extras/txttojson.py
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import pprint
|
||||||
|
#import re
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
except:
|
||||||
|
exit('You need pyYAML.')
|
||||||
|
|
||||||
|
def parseArgs():
|
||||||
|
args = argparse.ArgumentParser()
|
||||||
|
args.add_argument('-i',
|
||||||
|
'--in',
|
||||||
|
dest = 'infile',
|
||||||
|
required = True,
|
||||||
|
help = 'The plaintext representation of a python dict')
|
||||||
|
args.add_argument('-o',
|
||||||
|
'--out',
|
||||||
|
dest = 'outfile',
|
||||||
|
required = True,
|
||||||
|
help = 'The JSON file to create')
|
||||||
|
return(args)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = vars(parseArgs().parse_args())
|
||||||
|
infile = os.path.abspath(os.path.normpath(args['infile']))
|
||||||
|
outfile = os.path.abspath(os.path.normpath(args['outfile']))
|
||||||
|
if not os.path.lexists(infile):
|
||||||
|
exit('Input file doesn\'t exist.')
|
||||||
|
#try:
|
||||||
|
with open(outfile, 'w') as outgoing:
|
||||||
|
with open(infile, 'r') as incoming:
|
||||||
|
#data = re.sub("'", '"', incoming.read())
|
||||||
|
#outgoing.write(data)
|
||||||
|
#d = json.dumps(data, ensure_ascii = False)
|
||||||
|
#d = json.dumps(incoming.read().replace("'", '"'))
|
||||||
|
d = yaml.load(incoming.read())
|
||||||
|
pprint.pprint(d)
|
||||||
|
j = json.dumps(d, indent = 4)
|
||||||
|
outgoing.write(j)
|
||||||
|
#except:
|
||||||
|
#exit('Error when trying to read/write file(s).')
|
||||||
|
return()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user