systemrescue-zfs/airootfs/etc/systemd/scripts/sysrescue-initialize-prenet
Gerd v. Egidy 58169f4ed2 support configuring entries for the /etc/hosts file in the YAML config
Example config:

sysconfig:
    hosts:
        "192.168.1.1": "example.net.lan"
        "192.168.1.10": "foo.net.lan foo"
2022-12-11 21:16:30 +01:00

151 lines
5.9 KiB
Python
Executable file

#!/usr/bin/env python3
#
# initialize SystemRescue, do the parts that must be finished before networking is started
# Keep as short as possible, move non-critical parts to -whilenet to not block the boot unnecessarily
#
# SPDX-License-Identifier: GPL-3.0-or-later
import subprocess
import json
import glob
import os
import sys
import re
import tempfile
import functools
import configparser
# flush stdout buffer after each print call: immediately show the user what is going on
print = functools.partial(print, flush=True)
def strtobool (val):
"""Convert a string representation of truth to true (1) or false (0).
True values are 'y', 'yes', 't', 'true', 'on', '1', '1.0'; false values
are 'n', 'no', 'f', 'false', 'off', '0', '0.0'. Raises ValueError if
'val' is anything else.
Function adapted from Pythons distutils.util.py because it will be deprecated soon
Copyright (c) Python Software Foundation; All Rights Reserved
"""
val = str(val).lower()
if val in ('y', 'yes', 't', 'true', 'on', '1', '1.0'):
return True
elif val in ('n', 'no', 'f', 'false', 'off', '0', '0.0'):
return False
else:
raise ValueError("invalid truth value %r" % (val,))
# ==============================================================================
# Initialization
# ==============================================================================
print(f"====> Script {sys.argv[0]} starting ...")
errcnt = 0
# ==============================================================================
# Read the effective configuration file
# ==============================================================================
print(f"====> Read the effective configuration file ...")
effectivecfg = "/run/archiso/config/sysrescue-effective-config.json"
if os.path.exists(effectivecfg) == False:
print (f"Failed to find effective configuration file in {effectivecfg}")
sys.exit(1)
with open(effectivecfg) as file:
config = json.load(file)
# ==============================================================================
# Sanitize config, initialize variables
# Make sysrescue-initialize work safely without them being defined or have a wrong type
# Also show the effective configuration
# ==============================================================================
print(f"====> Showing the effective global configuration (except clear passwords) ...")
def read_cfg_value(scope, name, defaultval, printval):
if not scope in config:
val = defaultval
elif name in config[scope]:
chkval = config[scope][name]
try:
if isinstance(chkval, list) or isinstance(chkval, dict):
raise TypeError(f"must be a {type(defaultval)}, not a {type(chkval)}")
elif isinstance(defaultval, bool) and not isinstance(chkval, bool):
val = strtobool(chkval)
else:
val = type(defaultval)(chkval)
except (TypeError, ValueError) as e:
if printval:
print(f"config['{scope}']['{name}'] with {chkval} is not the same type as defaultval: {e}")
else:
print(f"config['{scope}']['{name}'] is not the same type as defaultval: {e}")
val = defaultval
else:
val = defaultval
if printval:
print(f"config['{scope}']['{name}']={val}")
return val
nofirewall = read_cfg_value('global','nofirewall', False, True)
# ==============================================================================
# Apply the effective configuration
# ==============================================================================
print(f"====> Applying pre-network configuration ...")
# Disable the firewall
if nofirewall == True:
# The firewall service(s) must be in the Before-section of sysrescue-initialize-prenet.service
p = subprocess.run(["systemctl", "disable", "--now", "iptables.service", "ip6tables.service"], text=True)
if p.returncode == 0:
print (f"Have disabled the firewall successfully")
else:
print (f"Failed to disable the firewall")
errcnt+=1
# ==============================================================================
# customize sysctl
# Should be pre-network to allow tweaking network-specific sysctls
# ==============================================================================
if 'sysconfig' in config and 'sysctl' in config['sysconfig'] and \
config['sysconfig']['sysctl'] and isinstance(config['sysconfig']['sysctl'], dict):
print(f"====> Customizing sysctl options ...")
sysctllines = ""
for key, value in config['sysconfig']['sysctl'].items():
sysctllines+=f"{key} = {value}\n"
# pipe config into sysctl
p = subprocess.run(["sysctl", "--load=-"], text=True, input=sysctllines)
if p.returncode != 0:
print (f"Some or all sysctl options couldn't be set")
errcnt+=1
# ==============================================================================
# configure hosts file
# Should be pre-network to be available throughout the whole network setup
# ==============================================================================
if 'sysconfig' in config and 'hosts' in config['sysconfig'] and \
config['sysconfig']['hosts'] and isinstance(config['sysconfig']['hosts'], dict):
print(f"====> Configuring /etc/hosts ...")
try:
# append all our entries to the hosts file
with open("/etc/hosts", "a") as hostsfile:
# key is the IPv4/IPv6, value the hostname(s)
for ip, hostname in config['sysconfig']['hosts'].items():
hostsfile.write(f"{ip}\t{hostname}\n")
hostsfile.close()
except Exception as e:
print(e)
errcnt+=1
# ==============================================================================
# End of the script
# ==============================================================================
print(f"====> Script {sys.argv[0]} completed with {errcnt} errors ...")
sys.exit(errcnt)