* New feature: deployment structure can now import/include other templates (Included templates will be installed first, since we'll assume those are baselines/requirements for slimmer deploy-structs)
* Deployment scripts strings now supports python string formatting, if parameter or is given as options to each command-line (TODO: Add as a global parameter as well, and treat all strings as formatable) * Added two templates: workstation + 00:11:22:33:44:55, a example of how to set up a workstation using a template and a custom addition. Also added a default template that is similar to the workstation but does everything in one template. They all use some awk magic to fix alt-tab in Awesome WM, it also creates a "desktop" environment and installs some useful tools and fixes the start menu in Awesome WM. * Reordering mirrors is now a configurable option (Default turned off, to better suit offline environments) * Disk/root password now configurable as either a fixed string, or ask for via STDIN (Syntax for now is: ) * deployment targets now a variable (todo: add a parameter/argument) * SSL support (ignores certificate validation for now, I know this is bad, but until a parameter etc is in place, this has to be a nessecary evil for now) * Cleaned up a lot of custom variables and baked them into so it's easier to format strings based off information gathered along the way (such as partition names). * Error handling: Mostly for missing dependencies and situations, such as not booted in UEFI environment
This commit is contained in:
parent
3b07cf27e8
commit
252af79e3d
162
archinstall.py
162
archinstall.py
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
import traceback
|
import traceback
|
||||||
import psutil, os, re, struct, sys, json
|
import psutil, os, re, struct, sys, json
|
||||||
import urllib.request, urllib.parse
|
import urllib.request, urllib.parse, ssl
|
||||||
from glob import glob
|
from glob import glob
|
||||||
#from select import epoll, EPOLLIN, EPOLLHUP
|
#from select import epoll, EPOLLIN, EPOLLHUP
|
||||||
from socket import socket, inet_ntoa, AF_INET, AF_INET6, AF_PACKET
|
from socket import socket, inet_ntoa, AF_INET, AF_INET6, AF_PACKET
|
||||||
|
|
@ -9,9 +9,13 @@ from collections import OrderedDict as oDict
|
||||||
from subprocess import Popen, STDOUT, PIPE
|
from subprocess import Popen, STDOUT, PIPE
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
|
## FIXME: dependency checks (fdisk, lsblk etc)
|
||||||
|
|
||||||
rootdir_pattern = re.compile('^.*?/devices')
|
rootdir_pattern = re.compile('^.*?/devices')
|
||||||
harddrives = oDict()
|
harddrives = oDict()
|
||||||
|
|
||||||
|
deploy_target = 'https://raw.githubusercontent.com/Torxed/archinstall/net-deploy/deployments'
|
||||||
|
|
||||||
args = {}
|
args = {}
|
||||||
positionals = []
|
positionals = []
|
||||||
for arg in sys.argv[1:]:
|
for arg in sys.argv[1:]:
|
||||||
|
|
@ -105,10 +109,11 @@ def grab_partitions(dev):
|
||||||
parts = oDict()
|
parts = oDict()
|
||||||
o = run('lsblk -o name -J -b {dev}'.format(dev=dev))
|
o = run('lsblk -o name -J -b {dev}'.format(dev=dev))
|
||||||
r = json.loads(o)
|
r = json.loads(o)
|
||||||
for part in r['blockdevices'][0]['children']:
|
if len(r['blockdevices']) and 'children' in r['blockdevices'][0]:
|
||||||
parts[part['name'][len(drive_name):]] = {
|
for part in r['blockdevices'][0]['children']:
|
||||||
# TODO: Grab partition info and store here?
|
parts[part['name'][len(drive_name):]] = {
|
||||||
}
|
# TODO: Grab partition info and store here?
|
||||||
|
}
|
||||||
|
|
||||||
return parts
|
return parts
|
||||||
|
|
||||||
|
|
@ -134,22 +139,64 @@ def multisplit(s, splitters):
|
||||||
|
|
||||||
def grab_url_data(path):
|
def grab_url_data(path):
|
||||||
safe_path = path[:path.find(':')+1]+''.join([item if item in ('/', '?', '=', '&') else urllib.parse.quote(item) for item in multisplit(path[path.find(':')+1:], ('/', '?', '=', '&'))])
|
safe_path = path[:path.find(':')+1]+''.join([item if item in ('/', '?', '=', '&') else urllib.parse.quote(item) for item in multisplit(path[path.find(':')+1:], ('/', '?', '=', '&'))])
|
||||||
response = urllib.request.urlopen(safe_path)
|
ssl_context = ssl.create_default_context()
|
||||||
|
ssl_context.check_hostname = False
|
||||||
|
ssl_context.verify_mode=ssl.CERT_NONE
|
||||||
|
response = urllib.request.urlopen(safe_path, context=ssl_context)
|
||||||
return response.read()
|
return response.read()
|
||||||
|
|
||||||
|
def get_instructions(target):
|
||||||
|
instructions = {}
|
||||||
|
try:
|
||||||
|
instructions = grab_url_data('{}/{}.json'.format(deploy_target, target))
|
||||||
|
except urllib.error.HTTPError:
|
||||||
|
print('[N] No instructions found called: {}'.format(target))
|
||||||
|
return instructions
|
||||||
|
|
||||||
|
print('[N] Found net-deploy instructions called: {}'.format(target))
|
||||||
|
try:
|
||||||
|
instructions = json.loads(instructions.decode('UTF-8'), object_pairs_hook=oDict)
|
||||||
|
except:
|
||||||
|
print('[E] JSON instructions failed to load for {}'.format(target))
|
||||||
|
traceback.print_exc()
|
||||||
|
sleep(5)
|
||||||
|
|
||||||
|
return instructions
|
||||||
|
|
||||||
|
def merge_dicts(d1, d2, before=True, overwrite=False):
|
||||||
|
""" Merges d2 into d1 """
|
||||||
|
if before:
|
||||||
|
d1, d2 = d2.copy(), d1.copy()
|
||||||
|
overwrite = True
|
||||||
|
|
||||||
|
for key, val in d2.items():
|
||||||
|
if key in d1:
|
||||||
|
if type(d1[key]) in [dict, oDict] and type(d2[key]) in [dict, oDict]:
|
||||||
|
d1[key] = merge_dicts(d1[key] if not before else d2[key], d2[key] if not before else d1[key], before=before, overwrite=overwrite)
|
||||||
|
elif overwrite:
|
||||||
|
d1[key] = val
|
||||||
|
else:
|
||||||
|
d1[key] = val
|
||||||
|
|
||||||
|
return d1
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
update_git() # Breaks and restarts the script if an update was found.
|
update_git() # Breaks and restarts the script if an update was found.
|
||||||
update_drive_list()
|
update_drive_list()
|
||||||
|
if not os.path.isdir('/sys/firmware/efi'):
|
||||||
|
print('[E] This script only supports UEFI-booted machines.')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
## Setup some defaults (in case no command-line parameters or netdeploy-params were given)
|
||||||
if not 'drive' in args: args['drive'] = list(harddrives.keys())[0] # First drive found
|
if not 'drive' in args: args['drive'] = list(harddrives.keys())[0] # First drive found
|
||||||
if not 'size' in args: args['size'] = '100%'
|
if not 'size' in args: args['size'] = '100%'
|
||||||
if not 'start' in args: args['start'] = '513MiB'
|
if not 'start' in args: args['start'] = '513MiB'
|
||||||
if not 'pwfile' in args: args['pwfile'] = '/tmp/diskpw'
|
if not 'pwfile' in args: args['pwfile'] = '/tmp/diskpw'
|
||||||
if not 'hostname' in args: args['hostname'] = 'Arcinstall'
|
if not 'hostname' in args: args['hostname'] = 'Arcinstall'
|
||||||
if not 'country' in args: args['country'] = 'SE' #all
|
if not 'country' in args: args['country'] = 'SE' # 'all' if we don't want country specific mirrors.
|
||||||
if not 'packages' in args: args['packages'] = ''
|
if not 'packages' in args: args['packages'] = '' # extra packages other than default
|
||||||
if not 'post' in args: args['post'] = 'reboot'
|
if not 'post' in args: args['post'] = 'reboot'
|
||||||
if not 'password' in args: args['password'] = '0000'
|
if not 'password' in args: args['password'] = '0000' # Default disk passord, can be <STDIN> or a fixed string
|
||||||
|
|
||||||
## == If we got networking,
|
## == If we got networking,
|
||||||
# Try fetching instructions for this box and execute them.
|
# Try fetching instructions for this box and execute them.
|
||||||
|
|
@ -160,28 +207,27 @@ if __name__ == '__main__':
|
||||||
print('[N] No network interfaces - No net deploy.')
|
print('[N] No network interfaces - No net deploy.')
|
||||||
else:
|
else:
|
||||||
for mac in locmac:
|
for mac in locmac:
|
||||||
try:
|
instructions = get_instructions(mac)
|
||||||
instructions = grab_url_data('https://raw.githubusercontent.com/Torxed/archinstall/net-deploy/deployments/{}.json'.format(mac))
|
|
||||||
except urllib.error.HTTPError:
|
|
||||||
print('[N] No instructions for this box on this mac: {}'.format(mac))
|
|
||||||
continue
|
|
||||||
|
|
||||||
#print('Decoding:', instructions)
|
|
||||||
try:
|
|
||||||
instructions = json.loads(instructions.decode('UTF-8'), object_pairs_hook=oDict)
|
|
||||||
except:
|
|
||||||
print('[E] JSON instructions failed to load for {}'.format(mac))
|
|
||||||
traceback.print_exc()
|
|
||||||
instructions = {}
|
|
||||||
sleep(5)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if 'args' in instructions:
|
if 'args' in instructions:
|
||||||
|
## == Recursively fetch instructions if "include" is found under {args: ...}
|
||||||
|
while 'include' in instructions['args']:
|
||||||
|
includes = instructions['args']['include']
|
||||||
|
print('[!] Importing net-deploy target: {}'.format(includes))
|
||||||
|
del(instructions['args']['include'])
|
||||||
|
if type(includes) in (dict, list):
|
||||||
|
for include in includes:
|
||||||
|
instructions = merge_dicts(instructions, get_instructions(include), before=True)
|
||||||
|
else:
|
||||||
|
instructions = merge_dicts(instructions, get_instructions(includes), before=True)
|
||||||
|
|
||||||
|
## Update arguments if we found any
|
||||||
for key, val in instructions['args'].items():
|
for key, val in instructions['args'].items():
|
||||||
args[key] = val
|
args[key] = val
|
||||||
else:
|
else:
|
||||||
print('[N] No gateway - No net deploy')
|
print('[N] No gateway - No net deploy')
|
||||||
|
|
||||||
|
if args['password'] == '<STDIN>': args['password'] = input('Enter a disk (and root) password: ')
|
||||||
print(args)
|
print(args)
|
||||||
|
|
||||||
if not os.path.isfile(args['pwfile']):
|
if not os.path.isfile(args['pwfile']):
|
||||||
|
|
@ -207,32 +253,47 @@ if __name__ == '__main__':
|
||||||
o = run('parted -s {drive} set 1 boot on'.format(**args))
|
o = run('parted -s {drive} set 1 boot on'.format(**args))
|
||||||
o = run('parted -s {drive} mkpart primary {start} {size}'.format(**args))
|
o = run('parted -s {drive} mkpart primary {start} {size}'.format(**args))
|
||||||
|
|
||||||
first, second = grab_partitions(args['drive']).keys()
|
args['paritions'] = grab_partitions(args['drive'])
|
||||||
o = run('mkfs.vfat -F32 {drive}{part1}'.format(**args, part1=first))
|
if len(args['paritions']) <= 0:
|
||||||
|
print('[E] No paritions were created on {drive}'.format(**args), o)
|
||||||
|
exit(1)
|
||||||
|
for index, part_name in enumerate(args['paritions']):
|
||||||
|
args['partition_{}'.format(index+1)] = part_name
|
||||||
|
|
||||||
|
o = run('mkfs.vfat -F32 {drive}{partition_1}'.format(**args))
|
||||||
|
if (b'mkfs.fat' not in o and b'mkfs.vfat' not in o) or b'command not found' in o:
|
||||||
|
print('[E] Could not setup {drive}{partition_1}'.format(**args), o)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
# "--cipher sha512" breaks the shit.
|
# "--cipher sha512" breaks the shit.
|
||||||
# TODO: --use-random instead of --use-urandom
|
# TODO: --use-random instead of --use-urandom
|
||||||
print('[N] Adding encryption to {drive}{part2}.'.format(**args, part2=second))
|
print('[N] Adding encryption to {drive}{partition_2}.'.format(**args))
|
||||||
o = run('cryptsetup -q -v --type luks2 --pbkdf argon2i --hash sha512 --key-size 512 --iter-time 10000 --key-file {pwfile} --use-urandom luksFormat {drive}{part2}'.format(**args, part2=second))
|
o = run('cryptsetup -q -v --type luks2 --pbkdf argon2i --hash sha512 --key-size 512 --iter-time 10000 --key-file {pwfile} --use-urandom luksFormat {drive}{partition_2}'.format(**args))
|
||||||
if not o.decode('UTF-8').strip() == 'Command successful.':
|
if not o.decode('UTF-8').strip() == 'Command successful.':
|
||||||
print('[E] Failed to setup disk encryption.')
|
print('[E] Failed to setup disk encryption.', o)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
o = run('cryptsetup open {drive}{part2} luksdev --key-file {pwfile} --type luks2'.format(**args, part2=second))
|
o = run('cryptsetup open {drive}{partition_2} luksdev --key-file {pwfile} --type luks2'.format(**args))
|
||||||
o = run('file /dev/mapper/luksdev') # /dev/dm-0
|
o = run('file /dev/mapper/luksdev') # /dev/dm-0
|
||||||
if b'cannot open' in o:
|
if b'cannot open' in o:
|
||||||
print('[E] Could not mount encrypted device.')
|
print('[E] Could not mount encrypted device.', o)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
print('[N] Creating btrfs filesystem inside {drive}{partition_2}'.format(**args))
|
||||||
o = run('mkfs.btrfs /dev/mapper/luksdev')
|
o = run('mkfs.btrfs /dev/mapper/luksdev')
|
||||||
|
if not b'UUID' in o:
|
||||||
|
print('[E] Could not setup btrfs filesystem.', o)
|
||||||
|
exit(1)
|
||||||
o = run('mount /dev/mapper/luksdev /mnt')
|
o = run('mount /dev/mapper/luksdev /mnt')
|
||||||
|
|
||||||
print('[N] Reordering mirrors.')
|
|
||||||
os.makedirs('/mnt/boot')
|
os.makedirs('/mnt/boot')
|
||||||
o = run('mount {drive}{part1} /mnt/boot'.format(**args, part1=first))
|
o = run('mount {drive}{partition_1} /mnt/boot'.format(**args))
|
||||||
o = run("wget 'https://www.archlinux.org/mirrorlist/?country={country}&protocol=https&ip_version=4&ip_version=6&use_mirror_status=on' -O /root/mirrorlist".format(**args))
|
|
||||||
o = run("sed -i 's/#Server/Server/' /root/mirrorlist")
|
print('[N] Reordering mirrors.')
|
||||||
o = run('rankmirrors -n 6 /root/mirrorlist > /etc/pacman.d/mirrorlist')
|
if 'mirrors' in args and args['mirrors'] and get_default_gateway_linux():
|
||||||
|
o = run("wget 'https://www.archlinux.org/mirrorlist/?country={country}&protocol=https&ip_version=4&ip_version=6&use_mirror_status=on' -O /root/mirrorlist".format(**args))
|
||||||
|
o = run("sed -i 's/#Server/Server/' /root/mirrorlist")
|
||||||
|
o = run('rankmirrors -n 6 /root/mirrorlist > /etc/pacman.d/mirrorlist')
|
||||||
|
|
||||||
pre_conf = {}
|
pre_conf = {}
|
||||||
if 'pre' in instructions:
|
if 'pre' in instructions:
|
||||||
|
|
@ -247,13 +308,21 @@ if __name__ == '__main__':
|
||||||
for title in pre_conf:
|
for title in pre_conf:
|
||||||
print('[N] Network prerequisit step: {}'.format(title))
|
print('[N] Network prerequisit step: {}'.format(title))
|
||||||
for command in pre_conf[title]:
|
for command in pre_conf[title]:
|
||||||
opts = pre_conf[title][command] if type(pre_conf[title][command]) in (dict, oDict) else {}
|
raw_command = command
|
||||||
|
opts = pre_conf[title][raw_command] if type(pre_conf[title][raw_command]) in (dict, oDict) else {}
|
||||||
if len(opts):
|
if len(opts):
|
||||||
print('[-] Options: {}'.format(opts))
|
if 'pass-args' in opts or 'format' in opts:
|
||||||
|
command = command.format(**args)
|
||||||
|
if 'pass-args' in opts:
|
||||||
|
del(opts['pass-args'])
|
||||||
|
elif 'format' in opts:
|
||||||
|
del(opts['format'])
|
||||||
|
else:
|
||||||
|
print('[-] Options: {}'.format(opts))
|
||||||
|
|
||||||
#print('[N] Command: {} ({})'.format(command, opts))
|
#print('[N] Command: {} ({})'.format(raw_command, opts))
|
||||||
o = run('{c}'.format(c=command), opts)
|
o = run('{c}'.format(c=command), opts)
|
||||||
if type(conf[title][command]) == bytes and len(conf[title][command]) and not conf[title][command] in o:
|
if type(conf[title][raw_command]) == bytes and len(conf[title][raw_command]) and not conf[title][raw_command] in o:
|
||||||
print('[W] Prerequisit step failed: {}'.format(o.decode('UTF-8')))
|
print('[W] Prerequisit step failed: {}'.format(o.decode('UTF-8')))
|
||||||
#print(o)
|
#print(o)
|
||||||
|
|
||||||
|
|
@ -261,6 +330,10 @@ if __name__ == '__main__':
|
||||||
o = run('pacman -Syy')
|
o = run('pacman -Syy')
|
||||||
o = run('pacstrap /mnt base base-devel btrfs-progs efibootmgr nano wpa_supplicant dialog {packages}'.format(**args))
|
o = run('pacstrap /mnt base base-devel btrfs-progs efibootmgr nano wpa_supplicant dialog {packages}'.format(**args))
|
||||||
|
|
||||||
|
if not os.path.isdir('/mnt/etc'):
|
||||||
|
print('[E] Failed to strap in packages', o)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
o = run('genfstab -pU /mnt >> /mnt/etc/fstab')
|
o = run('genfstab -pU /mnt >> /mnt/etc/fstab')
|
||||||
with open('/mnt/etc/fstab', 'a') as fstab:
|
with open('/mnt/etc/fstab', 'a') as fstab:
|
||||||
fstab.write('\ntmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0\n') # Redundant \n at the start? who knoes?
|
fstab.write('\ntmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0\n') # Redundant \n at the start? who knoes?
|
||||||
|
|
@ -299,8 +372,8 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
## For some reason, blkid and /dev/disk/by-uuid are not getting along well.
|
## For some reason, blkid and /dev/disk/by-uuid are not getting along well.
|
||||||
## And blkid is wrong in terms of LUKS.
|
## And blkid is wrong in terms of LUKS.
|
||||||
#UUID = run('blkid -s PARTUUID -o value {drive}{part2}'.format(**args, part2=second)).decode('UTF-8').strip()
|
#UUID = run('blkid -s PARTUUID -o value {drive}{partition_2}'.format(**args)).decode('UTF-8').strip()
|
||||||
UUID = run("ls -l /dev/disk/by-uuid/ | grep {basename}{part2} | awk '{awk}'".format(basename=os.path.basename(args['drive']), part2=second, awk='{print $9}')).decode('UTF-8').strip()
|
UUID = run("ls -l /dev/disk/by-uuid/ | grep {basename}{partition_2} | awk '{{print $9}}'".format(basename=os.path.basename(args['drive']), **args)).decode('UTF-8').strip()
|
||||||
with open('/mnt/boot/loader/entries/arch.conf', 'w') as entry:
|
with open('/mnt/boot/loader/entries/arch.conf', 'w') as entry:
|
||||||
entry.write('title Arch Linux\n')
|
entry.write('title Arch Linux\n')
|
||||||
entry.write('linux /vmlinuz-linux\n')
|
entry.write('linux /vmlinuz-linux\n')
|
||||||
|
|
@ -316,13 +389,16 @@ if __name__ == '__main__':
|
||||||
for title in conf:
|
for title in conf:
|
||||||
print('[N] Network Deploy: {}'.format(title))
|
print('[N] Network Deploy: {}'.format(title))
|
||||||
for command in conf[title]:
|
for command in conf[title]:
|
||||||
|
raw_command = command
|
||||||
opts = conf[title][command] if type(conf[title][command]) in (dict, oDict) else {}
|
opts = conf[title][command] if type(conf[title][command]) in (dict, oDict) else {}
|
||||||
if len(opts):
|
if len(opts):
|
||||||
print('[-] Options: {}'.format(opts))
|
print('[-] Options: {}'.format(opts))
|
||||||
|
if 'pass-args' in opts and opts['pass-args']:
|
||||||
|
command = command.format(**args)
|
||||||
|
|
||||||
#print('[N] Command: {} ({})'.format(command, opts))
|
#print('[N] Command: {} ({})'.format(command, opts))
|
||||||
o = run('arch-chroot /mnt {c}'.format(c=command), opts)
|
o = run('arch-chroot /mnt {c}'.format(c=command), opts)
|
||||||
if type(conf[title][command]) == bytes and len(conf[title][command]) and not conf[title][command] in o:
|
if type(conf[title][raw_command]) == bytes and len(conf[title][raw_command]) and not conf[title][raw_command] in o:
|
||||||
print('[W] Post install command failed: {}'.format(o.decode('UTF-8')))
|
print('[W] Post install command failed: {}'.format(o.decode('UTF-8')))
|
||||||
#print(o)
|
#print(o)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"args" : {
|
||||||
|
"include" : "workstation",
|
||||||
|
"user" : "anton",
|
||||||
|
"password" : "1111",
|
||||||
|
"drive" : "/dev/sdb",
|
||||||
|
"post" : "don't reboot"
|
||||||
|
},
|
||||||
|
"post" : {
|
||||||
|
"Setup a basic virtual environment": {
|
||||||
|
"mkdir -p /home/{user}/virts" : {"pass-args" : true},
|
||||||
|
"qemu-img create -f qcow2 /home/{user}/virts/test_deploy.qcow2 4G" : {"pass-args" : true},
|
||||||
|
"chown -R {user}.{user} /home/{user}/virts" : {"pass-args" : true}
|
||||||
|
},
|
||||||
|
"Setup user" : {
|
||||||
|
"useradd -m -G wheel -s /bin/bash anton" : null,
|
||||||
|
"sh -c \"echo {user}:{password} | chpasswd\"" : {"pass-args" : true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"args" : {
|
||||||
|
"password" : "<STDIN>",
|
||||||
|
"user" : "anton",
|
||||||
|
"_webbrowser" : "chromium",
|
||||||
|
"_window_manager" : "awesome",
|
||||||
|
"_keyboard_layout" : "sv-latin1"
|
||||||
|
},
|
||||||
|
"post" : {
|
||||||
|
"Install workstation packages": {
|
||||||
|
"pacman -Syy --noconfirm {_webbrowser} {_window_manager} openssh sshfs git dhclient ttf-freefont xorg-server xorg-xrandr xorg-xinit xterm nano wget pulseaudio pulseaudio-alsa pavucontrol smbclient cifs-utils xscreensaver" : null
|
||||||
|
},
|
||||||
|
"Enable autostarts": {
|
||||||
|
"systemctl enable dhcpcd" : null
|
||||||
|
},
|
||||||
|
"Setup desktop environment" : {
|
||||||
|
"sed -i 's/^twm &/#&/' /etc/X11/xinit/xinitrc" : null,
|
||||||
|
"sed -i 's/^xclock/#&/' /etc/X11/xinit/xinitrc" : null,
|
||||||
|
"sed -i 's/^xterm/#&/' /etc/X11/xinit/xinitrc" : null,
|
||||||
|
"sed -i 's/^exec xterm/#&/' /etc/X11/xinit/xinitrc" : null,
|
||||||
|
"sh -c \"echo 'setxkbmap se' >> /etc/X11/xinit/xinitrc\"" : null,
|
||||||
|
"sh -c \"echo 'xscreensaver -no-splash &' >> /etc/X11/xinit/xinitrc\"" : null,
|
||||||
|
"sh -c \"echo 'exec {_window_manager}' >> /etc/X11/xinit/xinitrc\"" : {"pass-args" : true},
|
||||||
|
"sh -c \"echo 'KEYMAP={_keyboard_layout}\nFONT=lat9w-16' >> /etc/vconsole.conf\"" : {"pass-args" : true},
|
||||||
|
"sh -c \"sed -i 's/{ \\\"open terminal\\\", terminal/{ \\\"Chromium\\\", \\\"chromium\\\" },\n &1/' /etc/xdg/awesome/rc.lua\"" : null,
|
||||||
|
"sh -c \"sed -i 's/{ \\\"open terminal\\\", terminal/{ \\\"File handler\\\", \\\"nemo\\\" },\n &1/' /etc/xdg/awesome/rc.lua\"" : null,
|
||||||
|
"sh -c \"sed -i 's/^globalkeys = gears.table.join(/&\n awful.key({ modkey, }, \\\"l\\\", function() awful.spawn(\\\"xscreensaver-command -lock &\\\") end),\n/' /etc/xdg/awesome/rc.lua\"" : null,
|
||||||
|
"sh -c \"awk -i inplace -v RS='' '{gsub(/awful.key\\({ modkey,.*?}, \\\"Tab\\\",.*?\\\"client\\\"}\\),/, \\\"awful.key({ modkey, }, \\\"Tab\\\",\\\n function ()\\\n awful.client.focus.byidx(-1)\\\n if client.focus then\\\n client.focus:raise()\\\n end\\\n end),\\\n awful.key({ modkey, \\\"Shift\\\" }, \\\"Tab\\\",\\\n function ()\\\n awful.client.focus.byidx(1)\\\n if client.focus then\\\n client.focus.raise()\\\n end\\\n end),\\\"); print}' /etc/xdg/awesome/rc.lua\"" : null,
|
||||||
|
"gsettings set org.nemo.desktop show-desktop-icons false" : null,
|
||||||
|
"xdg-mime default nemo.desktop inode/directory application/x-gnome-saved-search" : null
|
||||||
|
},
|
||||||
|
"Setup users" : {
|
||||||
|
"useradd -m -G wheel -s /bin/bash anton" : null,
|
||||||
|
"sh -c \"echo {user}:{password} | chpasswd\"" : {"pass-args" : true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"args" : {
|
||||||
|
"password" : "<STDIN>",
|
||||||
|
"_mediaplayer" : "lollypop gstreamer gst-plugins-good gnome-keyring",
|
||||||
|
"_webbrowser" : "chromium",
|
||||||
|
"_window_manager" : "awesome",
|
||||||
|
"_keyboard_layout" : "sv-latin1",
|
||||||
|
"_virtulization" : "qemu ovmf",
|
||||||
|
"post" : "don't reboot"
|
||||||
|
},
|
||||||
|
"post" : {
|
||||||
|
"Install workstation packages": {
|
||||||
|
"pacman -Syy --noconfirm openssh sshfs git {_webbrowser} {_mediaplayer} {_window_manager} {_virtulization} dhclient ttf-freefont xorg-server xorg-xrandr xorg-xinit xterm nano wget pulseaudio pulseaudio-alsa pavucontrol smbclient cifs-utils xscreensaver" : {"pass-args" : true}
|
||||||
|
},
|
||||||
|
"Setup virtulization" : {
|
||||||
|
"sh -c \"Description=\\\"Bridge for virtual machines\\\"\nInterface=br0\nConnection=bridge\nBindsToInterfaces=(eno1)\nIP=no\nExecUpPost=\\\"ip link set dev br0 address $(cat /sys/class/net/eno1/address); IP=dhcp; ip_set\\\"\nExecDownPre=\\\"IP=dhcp\\\"\n\n## Ignore (R)STP and immediately activate the bridge\nSkipForwardingDelay=yes\"" : null
|
||||||
|
},
|
||||||
|
"Setup desktop environment" : {
|
||||||
|
"sed -i 's/^twm &/#&/' /etc/X11/xinit/xinitrc" : null,
|
||||||
|
"sed -i 's/^xclock/#&/' /etc/X11/xinit/xinitrc" : null,
|
||||||
|
"sed -i 's/^xterm/#&/' /etc/X11/xinit/xinitrc" : null,
|
||||||
|
"sed -i 's/^exec xterm/#&/' /etc/X11/xinit/xinitrc" : null,
|
||||||
|
"sh -c \"echo 'setxkbmap se' >> /etc/X11/xinit/xinitrc\"" : null,
|
||||||
|
"sh -c \"echo 'xscreensaver -no-splash &' >> /etc/X11/xinit/xinitrc\"" : null,
|
||||||
|
"sh -c \"echo 'exec {_window_manager}' >> /etc/X11/xinit/xinitrc\"" : {"pass-args" : true},
|
||||||
|
"sh -c \"echo 'KEYMAP={_keyboard_layout}\nFONT=lat9w-16' >> /etc/vconsole.conf\"" : {"pass-args" : true},
|
||||||
|
"sh -c \"sed -i 's/{ \\\"open terminal\\\", terminal/{ \\\"Chromium\\\", \\\"chromium\\\" },\n &1/' /etc/xdg/awesome/rc.lua\"" : null,
|
||||||
|
"sh -c \"sed -i 's/{ \\\"open terminal\\\", terminal/{ \\\"File handler\\\", \\\"nemo\\\" },\n &1/' /etc/xdg/awesome/rc.lua\"" : null,
|
||||||
|
"sh -c \"sed -i 's/^globalkeys = gears.table.join(/&\n awful.key({ modkey, }, \\\"l\\\", function() awful.spawn(\\\"xscreensaver-command -lock &\\\") end),\n/' /etc/xdg/awesome/rc.lua\"" : null,
|
||||||
|
"sh -c \"awk -i inplace -v RS='' '{gsub(/awful.key\\({ modkey,.*?}, \\\"Tab\\\",.*?\\\"client\\\"}\\),/, \\\"awful.key({ modkey, }, \\\"Tab\\\",\n function ()\n awful.client.focus.byidx(-1)\n if client.focus then\n client.focus:raise()\n end\n end),\n awful.key({ modkey, \\\"Shift\\\" }, \\\"Tab\\\",\n function ()\n awful.client.focus.byidx(1)\n if client.focus then\n client.focus.raise()\n end\n end),\\\"); print}' /etc/xdg/awesome/rc.lua\"" : null,
|
||||||
|
"gsettings set org.nemo.desktop show-desktop-icons false" : null,
|
||||||
|
"xdg-mime default nemo.desktop inode/directory application/x-gnome-saved-search" : null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,24 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# offline_mirror_path - is used to temporarily store build AUR packages
|
||||||
|
# in order to "host" them to the build process.
|
||||||
|
# The path will be on the build machine, not inside the build itself.
|
||||||
|
|
||||||
work_dir=$1
|
work_dir=$1
|
||||||
arch=$2
|
arch=$2
|
||||||
offline_mirror_path="/tmp/aur_offline"
|
offline_mirror_path="/tmp/aur_offline"
|
||||||
|
|
||||||
# A func to download, build ...
|
# A func to download, build and host AUR packages to the ISO build process
|
||||||
build_aur () {
|
build_aur () {
|
||||||
old_dir=`pwd`
|
old_dir=`pwd`
|
||||||
package=$1
|
package=$1
|
||||||
# Prep with a build-user:
|
# Prep with a build-user (removed at the end):
|
||||||
|
# TODO: Check if already exists, if so, randomize name/don't remove at the end.
|
||||||
|
# TODO: Don't give permission to wheel, give it only to this user (easy, but needs debugging first)
|
||||||
useradd -m -G wheel builder
|
useradd -m -G wheel builder
|
||||||
sed -i 's/# %wheel ALL=(ALL) NO/%wheel ALL=(ALL) NO/' /etc/sudoers
|
sed -i 's/# %wheel ALL=(ALL) NO/%wheel ALL=(ALL) NO/' /etc/sudoers
|
||||||
|
|
||||||
|
# Extract the AUR package.
|
||||||
cd /tmp
|
cd /tmp
|
||||||
rm -rf ${package} ${package}.tar.gz
|
rm -rf ${package} ${package}.tar.gz
|
||||||
wget "https://aur.archlinux.org/cgit/aur.git/snapshot/${package}.tar.gz"
|
wget "https://aur.archlinux.org/cgit/aur.git/snapshot/${package}.tar.gz"
|
||||||
|
|
@ -24,18 +31,12 @@ build_aur () {
|
||||||
su - builder -c "(cd ${build_dir}; makepkg -s --noconfirm)" >/dev/null 2>&1
|
su - builder -c "(cd ${build_dir}; makepkg -s --noconfirm)" >/dev/null 2>&1
|
||||||
|
|
||||||
|
|
||||||
echo " => Adding ${package} to local AUR mirror"
|
echo " => Adding ${package} to local AUR hosting directory ${offline_mirror_path}"
|
||||||
mkdir -p ${offline_mirror_path}
|
mkdir -p ${offline_mirror_path}
|
||||||
sh -c "cp *.xz ${offline_mirror_path}/"
|
sh -c "cp *.xz ${offline_mirror_path}/"
|
||||||
sh -c "repo-add ${offline_mirror_path}/aur_offline.db.tar.gz ${offline_mirror_path}/*.xz"
|
sh -c "repo-add ${offline_mirror_path}/aur_offline.db.tar.gz ${offline_mirror_path}/*.xz"
|
||||||
if [[ -z $(cat ${old_dir}/packages.both | grep ${package}) ]]; then
|
|
||||||
# TODO: save a copy of ${old_dir}/packages.both ONCE, if it doesn't excist already.
|
|
||||||
# This in order to revert our AUR changes which will affect a re-build.
|
|
||||||
echo " => Adding ${package} to packages.both (from AUR)"
|
|
||||||
echo "${package}" >> ${old_dir}/packages.both
|
|
||||||
fi
|
|
||||||
|
|
||||||
## Long term storage inside the ISO? (if we want to install to disk, we need to pass this along)
|
## Long term storage inside the ISO? (if we want to install from CD to disk or host it to others)
|
||||||
# sh -c "mv *.xz ${old_dir}/$2/$1.pkg.tar.xz"
|
# sh -c "mv *.xz ${old_dir}/$2/$1.pkg.tar.xz"
|
||||||
|
|
||||||
cd ${old_dir}
|
cd ${old_dir}
|
||||||
|
|
@ -48,8 +49,10 @@ build_aur () {
|
||||||
echo "Starting to sync upstream changes to offline mirror."
|
echo "Starting to sync upstream changes to offline mirror."
|
||||||
rm -rf /tmp/sync /tmp/local
|
rm -rf /tmp/sync /tmp/local
|
||||||
|
|
||||||
echo " => Building AUR (Adding packages to packages.both as we go along)"
|
echo " => Building AUR packages (found in packages.aur)"
|
||||||
build_aur "lighttpd2-git"
|
for package in $(cat ${work_dir}/packages.aur); do
|
||||||
|
build_aur package
|
||||||
|
done
|
||||||
|
|
||||||
if [[ -z $(cat ${work_dir}/pacman.conf | grep '\[aur_offline\]') ]]; then
|
if [[ -z $(cat ${work_dir}/pacman.conf | grep '\[aur_offline\]') ]]; then
|
||||||
echo " => Adding offline mirror to the chroot environment"
|
echo " => Adding offline mirror to the chroot environment"
|
||||||
Loading…
Reference in New Issue