Compare commits

..

10 Commits

Author SHA1 Message Date
Bart Sjerps 052a88cd3b update 2026-07-10 10:18:21 +02:00
Bart Sjerps c5ea471a5a added isolinux cfg 2026-06-28 14:41:00 +02:00
Bart Sjerps 4085210dee update 2026-06-10 14:43:23 +02:00
Bart Sjerps 4f366bcddd update 2026-06-10 14:41:31 +02:00
Bart Sjerps 0a01479d24 update 2026-06-10 13:28:26 +02:00
Bart Sjerps e49e2d3909 update 2026-06-10 12:02:38 +02:00
Bart Sjerps 7d7938fcc7 update 2026-06-09 16:20:53 +02:00
Bart Sjerps e6b8b5325c update 2026-06-09 15:44:41 +02:00
Bart Sjerps 292047aac6 update 2026-06-09 15:35:06 +02:00
Bart Sjerps 67019ec6ad update 2026-05-27 09:12:36 +02:00
14 changed files with 935 additions and 41 deletions
+40
View File
@@ -0,0 +1,40 @@
Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# Archives
*.zip
# Swap files
*.swp
# Custom
*.iso
*.cfg
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
# requires lorax, genisoimage: dnf install lorax genisoimage
mkksiso --ks=/var/www/kickstart/rocky-9.cfg Rocky-9.7-x86_64-minimal.iso custom.iso
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/python3
import argparse
import crypt
parser = argparse.ArgumentParser()
parser.add_argument('password')
args = parser.parse_args()
print(crypt.crypt(args.password, crypt.mksalt(crypt.METHOD_SHA512)))
Executable
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
#============================================================================
# Title : make-iso
# Description : Make a custom Rocky Linux installable ISO
# ---------------------------------------------------------------------------
# requires lorax, genisoimage: dnf install lorax genisoimage
die() { echo "$(basename $0): [die] $@" >&2 ; exit 1 ; }
test $(id -u) == 0 || die "Run as root (sudo $(basename $0) <opts>"
rpm -q --quiet lorax || die "lorax not installed"
rpm -q --quiet genisoimage || die "genisoimage not installed"
# Setup temp working directory - clean it up when program ends
readonly WORKDIR=$(/bin/mktemp --tmpdir -d)
cleanup() { /bin/rm -rf ${WORKDIR:-/none} ; }
trap "cleanup" INT TERM HUP EXIT
topdir=$(git rev-parse --show-toplevel)
echo $topdir
isopath=/nfs/sw/os/rocky/Rocky-9.7-x86_64-minimal.iso
target=/nfs/pve/template/iso/custom.iso
ks=$topdir/kickstart/rocky-9.cfg
custom=$topdir/custom
cp -r $custom $WORKDIR
cp $ks $WORKDIR
test -f $target && sudo rm -f $target
$topdir/bin/mkksiso -a $WORKDIR/custom --ks=$WORKDIR/$(basename $ks) --custom_cfg $topdir/kickstart/isolinux.cfg $isopath $target
Executable
+637
View File
@@ -0,0 +1,637 @@
#!/usr/bin/python3
#
# Copyright (C) 2019 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import argparse
from collections import OrderedDict
import logging as log
import os
import shutil
import shlex
import subprocess
import sys
import tempfile
# Maximum filename length
MAX_FNAME = 253
def SplitCmdline(cmdline):
"""
Split the commandline into an OrderedDict of arguments
If the argument appears multiple times its entry will have a list of the values,
and its position in the dictionary will be that of the first occurrence.
If the argument has no value its entry will be [None]
Arguments with a single value will be [VALUE]
Quotes strings are maintained, and values may contain equals signs which
will be preserved.
"""
kernel_args = OrderedDict()
for a in shlex.split(cmdline):
if "=" in a:
k,v = a.split("=", 1)
else:
k, v = a, None
if k in kernel_args:
kernel_args[k].append(v)
else:
kernel_args[k] = [v]
return kernel_args
def quote(s):
"""
Return a quoted string if it contains spaces.
Otherwise just return the string.
"""
if " " in s:
return f"\"{s}\""
return s
def ListKernelArgs(kernel_args):
"""
Return a list of quoted kernel arguments and values
The dictionary is the output from SplitCmdline.
Values with spaces are quoted with ""
"""
kernel_cmdline = []
for k, vs in kernel_args.items():
for v in vs:
if v is None:
kernel_cmdline.append(f"{k}")
else:
kernel_cmdline.append(f"{k}={quote(v)}")
return kernel_cmdline
def JoinKernelArgs(kernel_args):
"""
Return a string of quoted kernel arguments and values
The dictionary is the output from SplitCmdline.
Values with spaces are quoted with ""
"""
return " ".join(ListKernelArgs(kernel_args))
def AlterKernelArgs(kernel_args, rm_args, add_args):
"""
Modify the kernel argument OrderedDict
This first removes all arguments listed in rm_args. It will ignore
arguments that are not present.
It then extends the arguments listed in the add_args dictionary if they are
already present, otherwise it adds them to kernel_args
It returns the modified kernel_args OrderedDict.
"""
# Remove arguments
for k in rm_args:
if k in kernel_args:
del kernel_args[k]
# Add new arguments and update existing ones
for k, vs in add_args.items():
if k in kernel_args:
kernel_args[k].extend(vs)
else:
kernel_args[k] = vs
return kernel_args
def WrapKernelArgs(kernel_args, width=80):
"""
Return a wordwrapped string
It breaks the lines at spaces inbetween commands,
preserving quoted strings verbatim.
"""
result = kernel_args[0]
cols = len(result)
for arg in kernel_args[1:]:
if 1 + cols + len(arg) > width:
result += "\n"
result += arg
cols = len(arg)
else:
result += " " + arg
cols = cols + len(arg) + 1
result += "\n"
return result
def GetISODetails(isopath):
"""
Use xorriso to list the contents of the iso and get the volume id
Metadata about the iso is output to stderr, file listing is sent to stdout.
Returns a tuple of volume id, and the list of files on the iso
"""
cmd = ["xorriso", "-indev", isopath, "-pkt_output", "on", "-find"]
out = subprocess.run(cmd, check=True, capture_output=True, env={"LANG": "C"})
volid = ""
for line in out.stderr.decode("utf-8").splitlines():
if line.startswith("Volume id"):
volid = shlex.split(line)[-1]
if not volid:
raise RuntimeError(f"{isopath} is missing a volume id")
# Files on the iso
# The files are on stdout and are prefixed with 'R:1:' for result lines with trailing newlines.
files = []
for line in out.stdout.decode("utf-8").splitlines():
if line.startswith("R:1:"):
files.append(os.path.normpath(shlex.split(line)[-1]))
return volid, files
def ExtractISOFiles(isopath, files, tmpdir):
"""
Extract the given files (which must exist on the iso) into the temporary
directory.
"""
# Make sure the user can write to any extracted directories using -chmod_r
cmd = ["osirrox", "-indev", isopath, "-chmod_r", "u+rwx", "/", "--"]
for f in files:
cmd.extend(["-extract", f, tmpdir + "/" + f])
cmd.extend(["-rollback_end"])
subprocess.run(cmd, check=True, capture_output=False, env={"LANG": "C"})
# From pylorax/treebuilder.py
# udev whitelist: 'a-zA-Z0-9#+.:=@_-' (see is_whitelisted in libudev-util.c)
udev_blacklist=' !"$%&\'()*,/;<>?[\\]^`{|}~' # ASCII printable, minus whitelist
udev_blacklist += ''.join(chr(i) for i in range(32)) # ASCII non-printable
def udev_escape(label):
"""
Escape the volume id label characters so they can be used on the ISO
"""
out = ''
for ch in label:
out += ch if ch not in udev_blacklist else '\\x%02x' % ord(ch)
return out
def CheckBigFiles(add_paths):
"""
Check file size and filename length for problems
Returns True if any file exceeds 4GiB
Raises a RuntimeError if any filename is longer than MAX_FNAME
This examines all the files included, so may take some time.
"""
big_file = False
for src in add_paths:
if os.path.isdir(src):
for top, dirs, files in os.walk(src):
for f in files + dirs:
if len(f) > MAX_FNAME:
raise RuntimeError("iso contains filenames that are too long: %s" % f)
if os.stat(top + "/" + f).st_size >= 4*1024**3:
big_file = True
else:
if len(src) > MAX_FNAME:
raise RuntimeError("iso contains filenames that are too long: %s" % f)
if os.stat(src).st_size >= 4*1024**3:
big_file = True
return big_file
def ImplantMD5(output_iso):
"""
Add md5 checksums to the final iso
"""
cmd = ["implantisomd5", output_iso]
log.debug(" ".join(cmd))
try:
subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
log.error(str(e))
raise RuntimeError("implantisomd5 failed")
def RebuildEFIBoot(input_iso, tmpdir):
"""
On x86 the efiboot.img needs to be rebuilt from the new /EFI/BOOT/ files
returns new efiboot.img file with a temporary name.
"""
if not os.path.exists(tmpdir+"/EFI/BOOT"):
raise RuntimeError("Missing mkefiboot requirement: EFI/BOOT")
# Extract the EFI directory files from the iso
with tempfile.TemporaryDirectory(prefix="mkksiso-") as tmpefi:
ExtractISOFiles(input_iso, ["EFI"], tmpefi)
# Copy the modified config files over
shutil.copytree(tmpdir+"/EFI", tmpefi+"/EFI", dirs_exist_ok=True)
efibootimg = tempfile.NamedTemporaryFile(prefix="efibootimg-")
cmd = ["mkefiboot", "--label=ANACONDA"]
if log.root.level < log.INFO:
cmd.append("--debug")
cmd.extend([tmpefi + "/EFI/BOOT", efibootimg.name])
log.debug(" ".join(cmd))
try:
subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
log.error(str(e))
raise RuntimeError("Running mkefiboot")
return efibootimg
def RebuildS390CDBoot(tmpdir):
"""
On s390x the cdboot.img needs to be rebuilt with the new cmdline arguments
"""
# First check for the needed files
missing = []
for f in ["images/kernel.img", "images/initrd.img", "images/cdboot.prm"]:
if not os.path.exists(tmpdir + "/" + f):
log.debug("Missing file %s", f)
missing.append(f)
if missing:
raise RuntimeError("Missing requirement %s" % ", ".join(missing))
cmd = ["mk-s390image", tmpdir + "/images/kernel.img", tmpdir + "/images/cdboot.img",
"-r", tmpdir + "/images/initrd.img",
"-p", tmpdir + "/images/cdboot.prm"]
log.debug(" ".join(cmd))
try:
subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
log.error(str(e))
raise RuntimeError("Running mk-s390image")
def GetCmdline(line, commands):
"""
Get the cmdline portion of a line that starts with a command
returns the indented command prefix, and the cmdline.
"""
for c in commands:
if c not in line:
continue
# The command must be the first non-whitespace word
first, _ = line.strip().split(" ", 1)
if first != c:
continue
indent, prefix, cmdline = line.partition(c)
return indent+prefix, cmdline.strip()
return "", line
def EditIsolinux(rm_args, add_args, replace_list, tmpdir, custom_cfg):
"""
Modify the cmdline for an isolinux.cfg
Remove args, add new arguments and change existing volid if requested
"""
orig_cfg = tmpdir + "/isolinux/isolinux.cfg"
if not os.path.exists(orig_cfg):
log.warning("No isolinux/isolinux.cfg file found")
return
# Edit the config file, save the new one as .new
with open(orig_cfg, "r") as in_fp:
with open(orig_cfg + ".new", "w") as out_fp:
for line in in_fp:
for from_item, to_item in replace_list:
if from_item in line:
line = line.replace(from_item, to_item)
prefix, cmdline = GetCmdline(line, ["append"])
if prefix:
args = SplitCmdline(cmdline)
new_args = AlterKernelArgs(args, rm_args, add_args)
out_fp.write(prefix+" "+JoinKernelArgs(new_args))
out_fp.write("\n")
else:
out_fp.write(line)
out_fp.close()
os.replace(orig_cfg + ".new", orig_cfg)
if custom_cfg:
log.info('using custom config %s', custom_cfg)
with open(custom_cfg, 'r') as src, open(orig_cfg, 'w') as tgt:
tgt.write(src.read())
else:
log.info('using default config')
def EditGrub2(rm_args, add_args, replace_list, tmpdir):
"""
Modify the cmdline for GRUB2 UEFI and BIOS config files
Add the new arguments and change existing volid if requested
"""
grub_cfgs = ["EFI/BOOT/grub.cfg", "EFI/BOOT/BOOT.conf",
"boot/grub2/grub.cfg", "boot/grub/grub.cfg"]
if not any(os.path.exists(tmpdir + "/" + c) for c in grub_cfgs):
log.warning("No grub config files found")
return
for cfg in grub_cfgs:
orig_cfg = tmpdir + "/" + cfg
if not os.path.exists(orig_cfg):
continue
with open(orig_cfg, "r") as in_fp:
with open(orig_cfg + ".new", "w") as out_fp:
for line in in_fp:
for from_item, to_item in replace_list:
if from_item in line:
line = line.replace(from_item, to_item)
# Some start with linux (BIOS/aarch64), others with linuxefi (x86_64)
prefix, cmdline = GetCmdline(line, ["linuxefi", "linux"])
if prefix:
args = SplitCmdline(cmdline)
new_args = AlterKernelArgs(args, rm_args, add_args)
out_fp.write(prefix+" "+JoinKernelArgs(new_args))
out_fp.write("\n")
else:
out_fp.write(line)
out_fp.close()
os.replace(orig_cfg + ".new", orig_cfg)
def EditS390(rm_args, add_args, replace_list, tmpdir):
"""
Modify the cmdline for s390 config files
Add the new arguments and change existing volid if requested
"""
s390_cfgs = ["images/generic.prm", "images/cdboot.prm"]
if not any(os.path.exists(tmpdir + "/" + c) for c in s390_cfgs):
log.warning("No s390 config files found")
return
for cfg in s390_cfgs:
orig_cfg = tmpdir + "/" + cfg
if not os.path.exists(orig_cfg):
log.warning("No %s file found", cfg)
continue
with open(orig_cfg, "r") as in_fp:
# Read the config file and turn it into a line
lines = in_fp.readlines()
cmdline = " ".join(l.strip() for l in lines)
# Replace the volid
for from_item, to_item in replace_list:
if from_item in cmdline:
cmdline = cmdline.replace(from_item, to_item)
args = SplitCmdline(cmdline)
new_args = AlterKernelArgs(args, rm_args, add_args)
cmdline = ListKernelArgs(new_args)
# Write the new config file, breaking at 80 columns
with open(orig_cfg + ".new", "w") as out_fp:
out_fp.write(WrapKernelArgs(cmdline, width=80))
out_fp.close()
os.replace(orig_cfg + ".new", orig_cfg)
def CheckDiscinfo(path):
"""
If the ISO contains a .discinfo file, check the arch against the host arch
Raises a RuntimeError if the arch does not match
"""
## TODO -- is this even needed with the new method of rebuilding the iso?
if os.path.exists(path):
with open(path) as f:
discinfo = [l.strip() for l in f.readlines()]
log.info("iso arch = %s", discinfo[2])
if os.uname().machine != discinfo[2]:
raise RuntimeError("iso arch does not match the host arch.")
def MakeKickstartISO(input_iso, output_iso, ks="", updates_image="", add_paths=None,
cmdline="", rm_args="", new_volid="", replace_list=None, implantmd5=True,
skip_efi=False, custom_cfg=None):
"""
Make a kickstart ISO from a boot.iso or dvd
"""
if add_paths is None:
add_paths = []
if replace_list is None:
replace_list = []
# Gather information about the input iso
old_volid, files = GetISODetails(input_iso)
if not old_volid and not new_volid:
raise RuntimeError("No volume id found, cannot create iso.")
log.debug("ISO files:")
for f in files:
log.debug(" %s", f)
# Extract files that match the known config files.
known_configs = set([".discinfo", "isolinux/isolinux.cfg",
"boot/grub2/grub.cfg", "boot/grub/grub.cfg",
"EFI/BOOT/BOOT.conf", "EFI/BOOT/grub.cfg",
"images/generic.prm", "images/cdboot.prm",
"images/kernel.img", "images/initrd.img"])
extract_files = set(files) & known_configs
with tempfile.TemporaryDirectory(prefix="mkksiso-") as tmpdir:
ExtractISOFiles(input_iso, extract_files, tmpdir)
CheckDiscinfo(tmpdir + "/.discinfo")
new_volid = new_volid or old_volid
log.info("Volume Id = %s", new_volid)
# Escape the volume ids
new_volid = udev_escape(new_volid)
old_volid = udev_escape(old_volid)
remove_args = rm_args.split(' ') if rm_args else []
add_args = SplitCmdline(cmdline)
if ks:
add_args["inst.ks"] = ["hd:LABEL=%s:/%s" % (new_volid or old_volid, os.path.basename(ks))]
add_paths.append(ks)
if updates_image:
add_args["inst.updates"] = ["hd:LABEL=%s:/%s" % (new_volid or old_volid, os.path.basename(updates_image))]
add_paths.append(updates_image)
replace_list.append((old_volid, new_volid))
log.debug(replace_list)
# Add kickstart command and optionally change the volid of the available config files
EditIsolinux(remove_args, add_args, replace_list, tmpdir, custom_cfg)
EditGrub2(remove_args, add_args, replace_list, tmpdir)
EditS390(remove_args, add_args, replace_list, tmpdir)
if os.uname().machine.startswith("s390"):
RebuildS390CDBoot(tmpdir)
# If this is a UEFI iso, rebuild the efiboot.img file and put it in /efiboot.img
efibootimg = None
if not skip_efi and ("EFI/BOOT/grub.cfg" in files or "EFI/BOOT/BOOT.conf" in files):
if os.getuid() != 0:
raise RuntimeError("mkefiboot requires root privileges")
efibootimg = RebuildEFIBoot(input_iso, tmpdir)
# Build the command to rebuild the iso with the changes and additions
cmd = ["xorriso", "-indev", input_iso, "-outdev", output_iso, "-boot_image", "any", "replay"]
if new_volid != old_volid:
cmd.extend(["-volid", new_volid])
# Replace the embedded efiboot.img on partition 2
if efibootimg:
cmd.extend(["-append_partition", "2", "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", efibootimg.name])
# Update the config files that were extracted and modified
for root, _, files in os.walk(tmpdir, topdown=False):
isoroot = root.replace(tmpdir, "")
for f in files:
cmd.extend(["-update", root + "/" + f, isoroot + "/" + f])
# Add the kickstart and the new files and directories
for p in add_paths:
cmd.extend(["-map", p, os.path.basename(p)])
check_paths = add_paths
if CheckBigFiles(check_paths):
if "-as" not in cmd:
cmd.extend(["-as", "mkisofs"])
cmd.extend(["-iso-level", "3"])
if os.uname().machine.startswith("ppc64le"):
if "-as" not in cmd:
cmd.extend(["-as", "mkisofs"])
cmd.extend(["-U"])
## NOTE: If any xorriso commands need to be added after this they need
## to be preceeded by an '--' entry to exit the '-as mkisofs' mode
log.debug("Running: %s", " ".join(cmd))
subprocess.run(cmd, check=True, capture_output=False, env={"LANG": "C"})
if implantmd5:
ImplantMD5(output_iso)
# Generate a report of the layout of the new iso
if log.root.level < log.INFO:
cmd = ["xorriso", "-indev", output_iso, "-report_el_torito", "plain", "-report_system_area", "plain"]
log.debug("Running: %s", " ".join(cmd))
subprocess.run(cmd, check=False, capture_output=False, env={"LANG": "C"})
def setup_arg_parser():
""" Return argparse.Parser object of cmdline."""
parser = argparse.ArgumentParser(description="Add a kickstart and files to an iso")
parser.add_argument("-a", "--add", action="append", dest="add_paths", default=[],
type=os.path.abspath,
help="File or directory to add to ISO (may be used multiple times)")
parser.add_argument("-c", "--cmdline", dest="cmdline", metavar="CMDLINE", default="",
help="Arguments to add to kernel cmdline")
parser.add_argument("-r", "--rm-args", dest="rm_args", metavar="ARGS", default="",
help="Space separated list of arguments to remove from the kernel cmdline")
parser.add_argument("--debug", action="store_const", const=log.DEBUG,
dest="loglevel", default=log.INFO,
help="print debugging info")
parser.add_argument("--no-md5sum", action="store_false", default=True,
help="Do not run implantisomd5 on the ouput iso")
parser.add_argument("--ks", type=os.path.abspath, metavar="KICKSTART",
help="Optional kickstart to add to the ISO (adding inst.ks automatically)")
parser.add_argument("-u", "--updates", type=os.path.abspath, metavar="IMAGE",
help="Optional updates image to add to the ISO (adding inst.updates automatically)")
parser.add_argument("-V", "--volid", dest="volid", help="Set the ISO volume id, defaults to input's", default=None)
parser.add_argument("-R", "--replace", nargs=2, action="append", metavar=("FROM", "TO"),
help="Replace string in grub.cfg. Can be used multiple times")
parser.add_argument("--skip-mkefiboot", action="store_true", dest="skip_efi",
help="Skip running mkefiboot")
parser.add_argument("ks_pos", nargs="?", type=os.path.abspath, metavar="KICKSTART",
help="Optional kickstart to add to the ISO")
parser.add_argument("input_iso", type=os.path.abspath, help="ISO to modify")
parser.add_argument("output_iso", type=os.path.abspath, help="Full pathname of iso to be created")
parser.add_argument("--custom_cfg", type=os.path.abspath, help="Full pathname of custom isolinux.cfg", metavar='CFG')
return parser
def main():
parser = setup_arg_parser()
args = parser.parse_args()
log.basicConfig(format='%(levelname)s:%(message)s', level=args.loglevel)
try:
errors = False
for t in ["xorriso", "osirrox"]:
if not shutil.which(t):
log.error("%s binary is missing", t)
errors = True
files = [args.input_iso, *args.add_paths]
if args.ks or args.ks_pos:
files += [args.ks or args.ks_pos]
for f in files:
if not os.path.exists(f):
log.error("%s is missing", f)
errors = True
if os.path.exists(args.output_iso):
log.error("%s already exists", args.output_iso)
errors = True
if "=" in args.rm_args:
log.error("--rm-args should only list the arguments to remove, not values")
errors = True
if args.ks and args.ks_pos:
log.error("Use either --ks KICKSTART or positional KICKSTART but not both")
errors = True
if not any([args.ks or args.ks_pos, args.updates, args.add_paths, args.cmdline, args.rm_args, args.volid, args.replace]):
log.error("Nothing to do - pass one or more of --ks, --updates, --add, --cmdline, --rm-args, --volid, --replace")
errors = True
if errors:
raise RuntimeError("Problems running %s" % sys.argv[0])
MakeKickstartISO(args.input_iso, args.output_iso, args.ks or args.ks_pos, args.updates,
args.add_paths, args.cmdline, args.rm_args,
args.volid, args.replace, args.no_md5sum, args.skip_efi, args.custom_cfg)
except RuntimeError as e:
log.error(str(e))
return 1
return 0
if __name__ == '__main__':
sys.exit(main())
+1
View File
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCdE/iMpuqJUG6FC3hLqOD5uREa6v6xXR3HeMBg1NibGVYkr0WmfvsckVsStKYA0SF3PLFs+fWTTJ6iFTDJvcclzADKe0REekWWrR7kNJR5RHoDwo6/hzm22tyGMH5i5JnvRElDmlLgmeXChWtqLVo2IP1JZrGyT/GTl4ViSZjNfdgCHJNxzmBgHdp31Mv9I7/1vv3A7ucJ3BJpbIL4Ck6QidFz1fQUWIJrXtNsdqvO/9PcFl/v75etfQRNPQ3HLMbWiQu6hVcKpxuwj0qVaXA+WPQAn5GeBKIkRYMsjEVC2fUS1/IVp47kmnXsw0H3fgGXPmoAEsRKs9niVOwegvWj workstation
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
dd if=/dev/zero of=/dev/sda bs=1M count=1000
poweroff
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
#============================================================================
# Title : lab-firstboot
# Description : Open a postinstall session on tty8 and run post-install
# ---------------------------------------------------------------------------
# Prevent openvt "could not deallocate" issue by redirecting stdin and stderr
exec 1>/dev/null
exec 2>/dev/null
# Don't run if homelab is already installed
test -f /etc/postinstall && exit
openvt -c 8 -w -f -s /var/lib/misc/custom/post-install.sh
sleep 15
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
#============================================================================
# Title : post-install
# Description :
# ---------------------------------------------------------------------------
rpm -q gpg-pubkey-350d275d-6279464b &>/dev/null || rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
dnf -y install epel-release bash-completion
test $(systemd-detect-virt) == "kvm" && dnf -y install qemu-guest-agent
systemctl is-active --quiet qemu-guest-agent || systemctl start qemu-guest-agent
dnf install -y dnf-automatic chrony langpacks-en glibc-langpack-nl screen wget tar bzip2 unzip lsof \
nscd nfs-utils tmpwatch autofs git nfs-utils net-tools sysstat bash-completion rsync vim atop htop iftop iotop pv dstat nmap
systemctl is-active --quiet autofs || systemctl enable --now autofs
touch /etc/postinstall
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
#============================================================================
# Title : post-install
# Description : postinstall section for running by Anaconda kickstart
# ---------------------------------------------------------------------------
mkdir -p /root/.ssh
cp /var/lib/misc/custom/postinstall.service /etc/systemd/system
cp /var/lib/misc/custom/authorized_keys /root/.ssh
chmod 600 /root/.ssh/authorized_keys
systemctl enable postinstall
+11
View File
@@ -0,0 +1,11 @@
[Unit]
Description=Postinstaller at first boot
After=network.target
[Service]
Type=simple
ExecStart=/var/lib/misc/custom/firstboot.sh
TimeoutStartSec=0
[Install]
WantedBy=default.target
+4
View File
@@ -0,0 +1,4 @@
TZ=Europe/Amsterdam
REPO=http://kickstart.lan/iso/Rocky-9.4-x86_64-minimal/minimal/
ROOTPW='$6$1mQhye0V5LujdR4F$87zIHy3bMZgjt02xY/F59eWk58VXh5CDSL0t9AInj6QOjLmYF0TDVeGLJH/bIKaGqXrbVJAgDHYZ9uT1uTMRX.'
+125
View File
@@ -0,0 +1,125 @@
default vesamenu.c32
timeout 600
display boot.msg
# Clear the screen when exiting the menu, instead of leaving the menu displayed.
# For vesamenu, this means the graphical background is still displayed without
# the menu itself for as long as the screen remains in graphics mode.
menu clear
menu background splash.png
menu title Rocky Linux Minimal 9.7
menu vshift 8
menu rows 18
menu margin 8
#menu hidden
menu helpmsgrow 15
menu tabmsgrow 13
# Border Area
menu color border * #00000000 #00000000 none
# Selected item
menu color sel 0 #ffffffff #00000000 none
# Title bar
menu color title 0 #ff7ba3d0 #00000000 none
# Press [Tab] message
menu color tabmsg 0 #ff3a6496 #00000000 none
# Unselected menu item
menu color unsel 0 #84b8ffff #00000000 none
# Selected hotkey
menu color hotsel 0 #84b8ffff #00000000 none
# Unselected hotkey
menu color hotkey 0 #ffffffff #00000000 none
# Help text
menu color help 0 #ffffffff #00000000 none
# A scrollbar of some type? Not sure.
menu color scrollbar 0 #ffffffff #ff355594 none
# Timeout msg
menu color timeout 0 #ffffffff #00000000 none
menu color timeout_msg 0 #ffffffff #00000000 none
# Command prompt text
menu color cmdmark 0 #84b8ffff #00000000 none
menu color cmdline 0 #ffffffff #00000000 none
# Do not display the actual menu unless the user presses a key. All that is displayed is a timeout message.
menu tabmsg Press Tab for full configuration options on menu items.
menu separator # insert an empty line
menu separator # insert an empty line
label linux
menu label ^Install Rocky Linux Minimal 9.7 (Homelab)
menu default
kernel vmlinuz
append initrd=initrd.img inst.stage2=hd:LABEL=Rocky-9-7-x86_64-dvd quiet inst.ks=hd:LABEL=Rocky-9-7-x86_64-dvd:/rocky-9.cfg
label check
menu label Test this ^media & install Rocky Linux Minimal 9.7
kernel vmlinuz
append initrd=initrd.img inst.stage2=hd:LABEL=Rocky-9-7-x86_64-dvd rd.live.check quiet inst.ks=hd:LABEL=Rocky-9-7-x86_64-dvd:/rocky-9.cfg
label fips
menu label ^Install Rocky Linux Minimal 9.7 in FIPS mode
kernel vmlinuz
append initrd=initrd.img inst.stage2=hd:LABEL=Rocky-9-7-x86_64-dvd quiet fips=1 inst.ks=hd:LABEL=Rocky-9-7-x86_64-dvd:/rocky-9.cfg
menu separator # insert an empty line
# utilities submenu
menu begin ^Troubleshooting
menu title Troubleshooting
label text
menu indent count 5
menu label Install Rocky Linux Minimal 9.7 using ^text mode
text help
Try this option out if you're having trouble installing
Rocky Linux Minimal 9.7.
endtext
kernel vmlinuz
append initrd=initrd.img inst.stage2=hd:LABEL=Rocky-9-7-x86_64-dvd inst.text quiet inst.ks=hd:LABEL=Rocky-9-7-x86_64-dvd:/rocky-9.cfg
label rescue
menu indent count 5
menu label ^Rescue a Rocky Linux Minimal system
text help
If the system will not boot, this lets you access files
and edit config files to try to get it booting again.
endtext
kernel vmlinuz
append initrd=initrd.img inst.stage2=hd:LABEL=Rocky-9-7-x86_64-dvd inst.rescue quiet inst.ks=hd:LABEL=Rocky-9-7-x86_64-dvd:/rocky-9.cfg
label memtest
menu label Run a ^memory test
text help
If your system is having issues, a problem with your
system's memory may be the cause. Use this utility to
see if the memory is working correctly.
endtext
kernel memtest
menu separator # insert an empty line
label local
menu label Boot from ^local drive
localboot 0xffff
menu separator # insert an empty line
menu separator # insert an empty line
label returntomain
menu label Return to ^main menu
menu exit
menu end
+17 -34
View File
@@ -8,8 +8,6 @@ firewall --service=ssh
selinux --disabled selinux --disabled
zerombr zerombr
repo --name="AppStream" --baseurl=http://atc-mgt01.dell-atc.lan/iso/Rocky-9.7-x86_64-minimal/Minimal
%include /tmp/settings %include /tmp/settings
reboot reboot
@@ -28,29 +26,23 @@ reboot
# Handling commandline options # # Handling commandline options #
# configuring repositories and setting up install packages # # configuring repositories and setting up install packages #
####################################################################################### #######################################################################################
%pre --log=/tmp/ks-pre.log %pre --log=/tmp/ks-pre.log --interpreter=/bin/bash
#!/bin/bash
echo Kickstart preinstall script echo Kickstart preinstall script
source /mnt/install/repo/custom/settings
touch /tmp/rpms /tmp/settings touch /tmp/rpms /tmp/settings
# Settings from config file # Settings from config file
rootpw='$6$OJEdzUbqfQR72WjX$SFMnDZ0MXM7JfYKPvvN0nJIPetzrWQw/0q360xgR9mwJVwrme4dt9hhtH95yytn8Ln0.0koVCno6vskylJFm5.' echo "repo --name=\"AppStream\" --baseurl=${REPO:-NO_REPO}" >> /tmp/settings
echo "rootpw --iscrypted ${ROOTPW:-NO_ROOTPW}" >> /tmp/settings
tz='Europe/Amsterdam' echo "timezone ${TZ:-Europe/Amsterdam}" >> /tmp/settings
set -- `cat /proc/cmdline` set -- `cat /proc/cmdline`
for I in $*; do case "$I" in *=*) eval ${I//inst\./} ;; esac; done for I in $*; do case "$I" in *=*) eval ${I//inst\./} ;; esac; done
grep -qws "debug" /proc/cmdline && bash
# Get release by probing libc
# EL 6 does not support bootdisk on XFS, only use it for everything else
case $(ls /lib64/libc-*|head -1) in
*2.12*) fs=ext4 ; mp=/mnt/source ;;
*) fs=xfs ; mp=/run/install/repo ;;
esac
# boot disk detection # boot disk detection
lsblk -bSo name,type,ro,hotplug,size,vendor,model,serial
bd=$(lsblk -nbSo name,type,ro,hotplug,size | awk 'NR==1 && $2=="disk" && $3==0 && $4==0 && $5>500 {print $1}')
printf "%-10s%10s%10s%10s\n" dev size removable inuse printf "%-10s%10s%10s%10s\n" dev size removable inuse
for dev in $(find /sys/block/ -name "sd?" -o -name "xvd?" -o -name "vd?"|sort); do for dev in $(find /sys/block/ -name "sd?" -o -name "xvd?" -o -name "vd?"|sort); do
devname=${dev##*/} devname=${dev##*/}
@@ -62,8 +54,6 @@ for dev in $(find /sys/block/ -name "sd?" -o -name "xvd?" -o -name "vd?"|sort);
done done
test -z "$bootdisk" && echo "No bootdisk detected" || echo "Bootdisk = $bootdisk" test -z "$bootdisk" && echo "No bootdisk detected" || echo "Bootdisk = $bootdisk"
echo "rootpw --iscrypted $rootpw" >> /tmp/settings
if test -d /sys/firmware/efi; then if test -d /sys/firmware/efi; then
cat <<- EOF >> /tmp/settings cat <<- EOF >> /tmp/settings
reqpart --add-boot reqpart --add-boot
@@ -71,18 +61,17 @@ if test -d /sys/firmware/efi; then
else else
cat <<- EOF >> /tmp/settings cat <<- EOF >> /tmp/settings
bootloader --location=mbr bootloader --location=mbr
part /boot --fstype=$fs --size=768 part /boot --fstype=xfs --size=1024
EOF EOF
fi fi
cat <<- EOF >> /tmp/settings cat <<- EOF >> /tmp/settings
timezone ${tz:---utc UTC}
ignoredisk --only-use=${bootdisk:-none} ignoredisk --only-use=${bootdisk:-none}
part pv.2 --grow --size=200 --maxsize=65536 part pv.2 --grow --size=200 --maxsize=65536
volgroup rvg --pesize=4096 pv.2 volgroup rvg --pesize=4096 pv.2
logvol / --fstype=$fs --name=root --vgname=rvg --size=1024 logvol / --fstype=xfs --name=root --vgname=rvg --size=1024
logvol /opt --fstype=xfs --name=opt --vgname=rvg --size=512 logvol /opt --fstype=xfs --name=opt --vgname=rvg --size=512
logvol /var --fstype=xfs --name=var --vgname=rvg --size=2048 logvol /var --fstype=xfs --name=var --vgname=rvg --size=4096
logvol /usr --fstype=xfs --name=usr --vgname=rvg --size=4096 logvol /usr --fstype=xfs --name=usr --vgname=rvg --size=4096
logvol /home --fstype=xfs --name=home --vgname=rvg --size=1024 logvol /home --fstype=xfs --name=home --vgname=rvg --size=1024
logvol /tmp --fstype=xfs --name=tmp --vgname=rvg --size=1024 logvol /tmp --fstype=xfs --name=tmp --vgname=rvg --size=1024
@@ -99,29 +88,23 @@ set > /tmp/environment
####################################################################################### #######################################################################################
# Post (no chroot) script # # Post (no chroot) script #
####################################################################################### #######################################################################################
%post --nochroot --log=/mnt/sysimage/var/log/ks-post-nochroot.log %post --nochroot --log=/mnt/sysimage/var/log/ks-post-nochroot.log --interpreter=/bin/bash
# Save kickstart and cmdline settings for later reference # Save kickstart and cmdline settings for later reference
cp /proc/cmdline /tmp/{settings,environment,rpms,ks-pre.log} /mnt/sysimage/var/lib/misc/ cp /proc/cmdline /tmp/{settings,environment,rpms,ks-pre.log} /mnt/sysimage/var/lib/misc/
# Prepare post-install
cp -r /mnt/install/repo/custom /mnt/sysimage/var/lib/misc/
%end %end
####################################################################################### #######################################################################################
# Post (chroot) script (optional customization) # # Post (chroot) script (optional customization) #
####################################################################################### #######################################################################################
%post --log=/var/log/ks-post-chroot.log --interpreter=/bin/bash %post --log=/var/log/ks-post-chroot.log --interpreter=/bin/bash
mkdir -p /root/.ssh
cat <<- EOF >> /root/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCdE/iMpuqJUG6FC3hLqOD5uREa6v6xXR3HeMBg1NibGVYkr0WmfvsckVsStKYA0SF3PLFs+fWTTJ6iFTDJvcclzADKe0REekWWrR7kNJR5RHoDwo6/hzm22tyGMH5i5JnvRElDmlLgmeXChWtqLVo2IP1JZrGyT/GTl4ViSZjNfdgCHJNxzmBgHdp31Mv9I7/1vv3A7ucJ3BJpbIL4Ck6QidFz1fQUWIJrXtNsdqvO/9PcFl/v75etfQRNPQ3HLMbWiQu6hVcKpxuwj0qVaXA+WPQAn5GeBKIkRYMsjEVC2fUS1/IVp47kmnXsw0H3fgGXPmoAEsRKs9niVOwegvWj /home/bart/.ssh/id_rsa
EOF
chmod 400 /root/.ssh/authorized_keys
chvt 2 # Run post-install script
iotty=$(tty) /var/lib/misc/custom/post-setup.sh
exec > "$iotty" 2>&1 < "$iotty"
read -p "Enter hostname: " hn
hostnamectl hostname $hn
%end %end