commit 6be518a3abc613976c08cec01710c73fbe5ca36e Author: Nicolas Massé Date: Tue May 27 20:49:56 2025 +0200 initial commit diff --git a/bootc/.gitignore b/bootc/.gitignore new file mode 100644 index 0000000..5609933 --- /dev/null +++ b/bootc/.gitignore @@ -0,0 +1,8 @@ +/etc +*.pem +auth.json +cache-*/ +*.iso +*.qcow2 +*.tar +osbuild.ks diff --git a/bootc/Containerfile b/bootc/Containerfile new file mode 100644 index 0000000..b6367ac --- /dev/null +++ b/bootc/Containerfile @@ -0,0 +1,32 @@ +FROM registry.redhat.io/rhel9/rhel-bootc:9.4 + +ARG ADMIN_USERNAME=demo \ + ADMIN_PASSWORD=redhat \ + NVIDIA_KERNEL_VERSION=5.14.0-427.22.1.el9_4 + +RUN set -Eeuo pipefail ; \ + if ! grep -qxF 'keepcache=1'; then \ + sed -i.bak '/^\[main\]$/a keepcache=1' /etc/dnf/dnf.conf ; \ + fi ; \ + echo "Replacing current kernel with a version compatible with the kernel modules shipped by Nvidia" ; \ + mkdir -p /tmp/rpms ; \ + dnf download -y --destdir /tmp/rpms kernel{,-core,-modules,-modules-core}-$NVIDIA_KERNEL_VERSION ; \ + rpm-ostree override replace /tmp/rpms/*.rpm ; \ + rm -rf /tmp/rpms ; \ + dnf config-manager --enable codeready-builder-for-rhel-9-$(arch)-rpms ; \ + dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm ; \ + dnf install -y mkpasswd NetworkManager-wifi podman skopeo git mosquitto ; \ + if [[ "$(arch)" == "aarch64" ]]; then \ + echo "Installing the Nvidia stuff..." ; \ + curl -sSfL -o /etc/yum.repos.d/nvidia-l4t.repo https://repo.download.nvidia.com/jetson/rhel-9.4/r36.3.1/nvidia-l4t.repo ; \ + curl -sSfL -o /etc/yum.repos.d/nvidia-container-toolkit.repo https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo ; \ + dnf config-manager --enable nvidia-container-toolkit-experimental ; \ + dnf install -y nvidia-jetpack-kmod nvidia-jetpack-all nvidia-container-toolkit-base ; \ + fi ; \ + useradd -m -G wheel -p "$(echo -n "$ADMIN_PASSWORD" | mkpasswd -m bcrypt --stdin)" "$ADMIN_USERNAME" + +ADD --chown=root:root root / + +RUN set -Eeuo pipefail ; \ + systemctl enable nvidia-ctk-init.service ; \ + systemctl enable repo-intelligent-train.service diff --git a/bootc/artefacts-iso.sh b/bootc/artefacts-iso.sh new file mode 100755 index 0000000..e54c769 --- /dev/null +++ b/bootc/artefacts-iso.sh @@ -0,0 +1,163 @@ +#!/bin/sh + +set -Eeuo pipefail + +# Source variables and environment +source ./env.sh + +# Kernel command line params per architecture +# Note: You can use multiple console= options; boot messages will be displayed on all consoles, but anaconda will put its display on the last console listed. +declare -A ARCH_KERNEL_CMDLINE=(["aarch64"]="console=ttyTCU0 console=tty0" ["x86_64"]="console=ttyS0 console=tty0") + +### +### KICKSTART +### + +## +## If you need to embed a file in the kickstart (pre/post script), encode it in Base32 as such: +## + +# umask 0700 +# mkdir -p \$XDG_RUNTIME_DIR/containers +# base32 -d > \$XDG_RUNTIME_DIR/containers/auth.json <<"EOB32" +# $(base32 -w 80 auth.json) +# EOB32 + +declare -a KICKSTART_ADDITIONAL_FILES_TAR_CMD_PRE=( ) +declare -a KICKSTART_ADDITIONAL_FILES_TAR_CMD_POST=( tar -zc -C post --owner=root --group=root . ) +declare -A KICKSTART_SNIPPETS=() +KICKSTART_SNIPPETS+=( ["restart networkmanager"]=" +systemctl restart --no-block NetworkManager.service +" ) +KICKSTART_SNIPPETS+=( ["bootc switch"]=" +bootc switch --mutate-in-place --transport registry $TARGET_IMAGE +" ) +KICKSTART_SNIPPETS+=( ["/etc/ostree/auth.json"]=" +base32 -d > /etc/ostree/auth.json <<\"EOB32\" +$(base32 -w 80 auth.json) +EOB32 +chmod 600 /etc/ostree/auth.json +" ) +KICKSTART_SNIPPETS+=( ["/etc/containers/registries.conf.d/bootc-registry.conf"]=" +cat > /etc/containers/registries.conf.d/bootc-registry.conf <<\"EOF\" +[[registry]] +location=\"${TARGET_IMAGE%%/*}\" +insecure=true +EOF +" ) + +# Inject NetworkManager connections to kickstart +KICKSTART_SNIPPETS+=( ["/etc/NetworkManager/system-connections"]="" ) +if [ -d root/etc/NetworkManager/system-connections ]; then + for file in root/etc/NetworkManager/system-connections/*.nmconnection; do + filename="$(basename "$file")" + KICKSTART_SNIPPETS["/etc/NetworkManager/system-connections"]+=" +base32 -d > \"/etc/NetworkManager/system-connections/$filename\" <<\"EOB32\" +$(base32 -w 80 "$file") +EOB32 +" + done +fi + +# Inject arbitrary files in kickstart +if [ -d pre ]; then + KICKSTART_SNIPPETS+=( ["additional files pre"]=" +base32 -d <<\"EOB32\" | tar -zx -C / --warning=none +$(cd pre && tar -zc --owner=root --group=root * | base32 -w 80) +EOB32 +" ) +else + KICKSTART_SNIPPETS+=( ["additional files pre"]="" ) +fi +if [ -d post ]; then + KICKSTART_SNIPPETS+=( ["additional files post"]=" +base32 -d <<\"EOB32\" | tar -zx -C / --warning=none +$(cd post && tar -zc --owner=root --group=root * | base32 -w 80) +EOB32 +" ) +else + KICKSTART_SNIPPETS+=( ["additional files post"]="" ) +fi + +KICKSTART_PREPOST_ONLINE=" +## +## Pre/post-install scripts +## + +%pre --interpreter=/bin/bash --logfile=/tmp/anaconda-pre.log --erroronfail +set -Eeuo pipefail +${KICKSTART_SNIPPETS["/etc/ostree/auth.json"]} +${KICKSTART_SNIPPETS["/etc/containers/registries.conf.d/bootc-registry.conf"]} +${KICKSTART_SNIPPETS["/etc/NetworkManager/system-connections"]} +${KICKSTART_SNIPPETS["additional files pre"]} +${KICKSTART_SNIPPETS["restart networkmanager"]} +%end + +%post --interpreter=/bin/bash --logfile=/var/log/anaconda-post.log --erroronfail +set -Eeuo pipefail +${KICKSTART_SNIPPETS["/etc/ostree/auth.json"]} +${KICKSTART_SNIPPETS["/etc/containers/registries.conf.d/bootc-registry.conf"]} +${KICKSTART_SNIPPETS["/etc/NetworkManager/system-connections"]} +${KICKSTART_SNIPPETS["additional files post"]} + +%end +" +KICKSTART_PREPOST_OFFLINE=" +## +## Pre/post-install scripts +## + +%pre --interpreter=/bin/bash --logfile=/tmp/anaconda-pre.log --erroronfail +${KICKSTART_SNIPPETS["additional files pre"]} +${KICKSTART_SNIPPETS["restart networkmanager"]} +%end + +%post --interpreter=/bin/bash --logfile=/var/log/anaconda-post.log --erroronfail +set -Eeuo pipefail +${KICKSTART_SNIPPETS["/etc/ostree/auth.json"]} +${KICKSTART_SNIPPETS["/etc/containers/registries.conf.d/bootc-registry.conf"]} +${KICKSTART_SNIPPETS["bootc switch"]} +${KICKSTART_SNIPPETS["additional files post"]} +%end +" +declare -A KICKSTART_PREPOST=(["online"]="$KICKSTART_PREPOST_ONLINE" ["offline"]="$KICKSTART_PREPOST_OFFLINE") + +# Types of ISO with kickstart to build +declare -a KICKSTART_TYPES=("online" "offline") + +ARCH="$(arch)" +for type in "${KICKSTART_TYPES[@]}"; do + KICKSTART_FILE="template-$type.ks" + echo "Templating Kickstart $KICKSTART_FILE..." + ( + export ARCH + export TARGET_IMAGE + export KERNEL_CMDLINE="${ARCH_KERNEL_CMDLINE[$ARCH]}" + envsubst < "$KICKSTART_FILE" > osbuild.ks + echo "${KICKSTART_PREPOST[$type]}" >> osbuild.ks + ) + + echo "Validating Kickstart..." + ksvalidator osbuild.ks + + if [[ "$type" == "offline" ]]; then + echo "Exporting container image..." + # Shortcut: tag the container image as if it had been pulled from the registry (save a roundtrip with the registry) + podman tag localhost/$NAME-$ARCH $TARGET_IMAGE + # Export the container image as oci-dir to embed it later in the + mkdir -p cache-$ARCH + rm -rf cache-$ARCH/container + podman save --format oci-dir -o cache-$ARCH/container $TARGET_IMAGE + # Remove shortcut to prevent side effects + podman rmi $TARGET_IMAGE + fi + + echo "Injecting artefacts into ISO $type..." + rm -f "install-$NAME-$ARCH-$type.iso" + if [[ "$type" == "offline" ]]; then + mkkiso_extra_args="-a cache-$ARCH/container" + else + mkkiso_extra_args="" + fi + mkksiso -R 'set timeout=60' 'set timeout=5' -R 'set default="1"' 'set default="0"' -c "${ARCH_KERNEL_CMDLINE[$ARCH]}" $mkkiso_extra_args --ks "osbuild.ks" "rhel-$RHEL_VERSION-$ARCH-boot.iso" "install-$NAME-$ARCH-$type.iso" +done diff --git a/bootc/artefacts-qcow2.sh b/bootc/artefacts-qcow2.sh new file mode 100755 index 0000000..f5cc70f --- /dev/null +++ b/bootc/artefacts-qcow2.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +set -Eeuo pipefail + +# Source variables and environment +source ./env.sh + +function bootc_image_builder () { + local type="$1" + local rpmmd="$2" + local store="$3" + local output="$4" + local config_file="$5" + local image="$6" + shift 6 + local -a args=("$@") + echo "Running bootc-image-builder with type = '$type', image = '$image' and opts = '$@'..." + podman run --rm --network "$PODMAN_NETWORK" --privileged --security-opt label=type:unconfined_t \ + -v "$config_file:/config.toml:ro" -v "$output:/output" -v "$rpmmd:/rpmmd" -v "$store:/store" \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + -v "$REGISTRY_AUTH_FILE:/auth.json:ro" -e "REGISTRY_AUTH_FILE=/auth.json" \ + "$BOOTC_IMAGE:$RHEL_VERSION" --type "$type" --config /config.toml "$image" "${args[@]}" +} + +arch="$(arch)" +mkdir -p cache-$arch/{rpmmd,store,output} + +# Shortcut: tag the container image as if it had been pulled from the registry (save a roundtrip with the registry) +podman tag localhost/$NAME-$arch $TARGET_IMAGE + +# Build ISO with Kickstart +#bootc_image_builder iso "$PWD/image-$arch/rpmmd" "$PWD/image-$arch/store" "$PWD/image-$arch/output" "$PWD/config-iso.toml" "$TARGET_IMAGE" --local --log-level info +#cp "image-$arch/output/bootiso/install.iso" "install-$NAME-$arch.iso" + +# Build qcow2 +bootc_image_builder qcow2 "$PWD/cache-$arch/rpmmd" "$PWD/cache-$arch/store" "$PWD/cache-$arch/output" "$PWD/config-qcow2.toml" "$TARGET_IMAGE" --local +cp "cache-$arch/output/qcow2/disk.qcow2" "disk-$NAME-$arch.qcow2" + +# Remove shortcut to prevent side effects +podman rmi $TARGET_IMAGE diff --git a/bootc/build.sh b/bootc/build.sh new file mode 100755 index 0000000..d3ab6e1 --- /dev/null +++ b/bootc/build.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +set -Eeuo pipefail + +# Source variables and environment +source ./env.sh + +# Login to registries, pull, etc. +./common.sh + +# Build images +declare -A PODMAN_ARCH_OPTS=(["aarch64"]="--platform linux/arm64/v8" ["x86_64"]="--platform linux/amd64") +for arch in "${ARCHITECTURES[@]}"; do + echo "Building $NAME image for $arch..." + rm -rf etc + tar -xf etc-$arch.tar + mkdir -p cache-$arch/dnf cache-$arch/rpm-ostree + podman build ${PODMAN_ARCH_OPTS[$arch]} --no-cache --from "$RHEL_IMAGE-$arch:$RHEL_VERSION" \ + -v $PWD/etc/pki/entitlement/:/etc/pki/entitlement:z -v $PWD/etc/rhsm:/etc/rhsm:z \ + -v $PWD/etc/pki/entitlement/:/run/secrets/etc-pki-entitlement:z -v $PWD/etc/rhsm:/run/secrets/rhsm:z \ + -v $PWD/etc/yum.repos.d:/etc/yum.repos.d:z -v $PWD/cache-$arch/dnf:/var/cache/dnf:z \ + -v $PWD/cache-$arch/rpm-ostree:/var/cache/rpm-ostree:z \ + --network $PODMAN_NETWORK -t localhost/$NAME-$arch . + podman save --format oci-archive -o $NAME-$arch.tar localhost/$NAME-$arch +done + +# Push Manifest +echo "Pushing to $TARGET_IMAGE..." +read -p "Press enter to continue " +if podman manifest exists localhost/$NAME; then + podman manifest rm localhost/$NAME +fi +podman manifest create localhost/$NAME +for arch in "${ARCHITECTURES[@]}"; do + podman manifest add localhost/$NAME localhost/$NAME-$arch +done +podman manifest push localhost/$NAME $TARGET_IMAGE diff --git a/bootc/common.sh b/bootc/common.sh new file mode 100755 index 0000000..81b5d38 --- /dev/null +++ b/bootc/common.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +# Source variables and environment +source ./env.sh + +# Pre-requisites +if ! podman network exists $PODMAN_NETWORK; then + podman network create $PODMAN_NETWORK --disable-dns +fi + +# Login to registries +if [ ! -f "$REGISTRY_AUTH_FILE" ]; then + echo "Logging in registry.redhat.io" + podman login registry.redhat.io + echo "Logging in quay.io registry" + podman login quay.io + echo "Done" + read -p "Press enter to continue " +fi + +# Pull +echo "Pulling images..." +if ! podman image exists $BOOTC_IMAGE:$RHEL_VERSION; then + podman pull $BOOTC_IMAGE:$RHEL_VERSION +fi +if ! podman image exists $RHEL_IMAGE-x86_64:$RHEL_VERSION; then + podman rmi -i $RHEL_IMAGE:$RHEL_VERSION + podman pull --platform linux/amd64 $RHEL_IMAGE:$RHEL_VERSION + podman tag $RHEL_IMAGE:$RHEL_VERSION $RHEL_IMAGE-x86_64:$RHEL_VERSION + podman rmi $RHEL_IMAGE:$RHEL_VERSION +fi +if ! podman image exists $RHEL_IMAGE-aarch64:$RHEL_VERSION; then + podman rmi -i $RHEL_IMAGE:$RHEL_VERSION + podman pull --platform linux/arm64/v8 $RHEL_IMAGE:$RHEL_VERSION + podman tag $RHEL_IMAGE:$RHEL_VERSION $RHEL_IMAGE-aarch64:$RHEL_VERSION + podman rmi $RHEL_IMAGE:$RHEL_VERSION +fi diff --git a/bootc/config-iso.toml b/bootc/config-iso.toml new file mode 100644 index 0000000..7909f04 --- /dev/null +++ b/bootc/config-iso.toml @@ -0,0 +1,12 @@ +[customizations.installer.kickstart] +contents = """ +lang fr_FR.UTF-8 +keyboard fr +timezone UTC +rootpw --lock +zerombr +clearpart --all --initlabel +autopart --type=plain +reboot --eject +bootloader --append="console=tty0 console=ttyS0" +""" diff --git a/bootc/config-qcow2.toml b/bootc/config-qcow2.toml new file mode 100644 index 0000000..e69de29 diff --git a/bootc/env.sh b/bootc/env.sh new file mode 100644 index 0000000..7eb0851 --- /dev/null +++ b/bootc/env.sh @@ -0,0 +1,17 @@ +### +### General +### +PODMAN_NETWORK="edge-ai" +RHEL_VERSION="9.4" +RHEL_IMAGE="registry.redhat.io/rhel9/rhel-bootc" +BOOTC_IMAGE="registry.redhat.io/rhel9/bootc-image-builder" +NAME="bootc-edge-ai" +TARGET_IMAGE="quay.io/nmasse-redhat/$NAME:latest" + +# All architectures to build for +declare -a ARCHITECTURES=("x86_64" "aarch64") + +### +### Environment Variables +### +export REGISTRY_AUTH_FILE="$PWD/auth.json" diff --git a/bootc/post/etc/NetworkManager/system-connections/.gitignore b/bootc/post/etc/NetworkManager/system-connections/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/bootc/post/etc/NetworkManager/system-connections/.gitignore @@ -0,0 +1 @@ +* diff --git a/bootc/post/etc/NetworkManager/system-connections/Sample-Wifi.nmconnection b/bootc/post/etc/NetworkManager/system-connections/Sample-Wifi.nmconnection new file mode 100644 index 0000000..8e12ace --- /dev/null +++ b/bootc/post/etc/NetworkManager/system-connections/Sample-Wifi.nmconnection @@ -0,0 +1,23 @@ +[connection] +id=Sample-Wifi +uuid=e6b2f736-4787-43f2-866d-996ad025d95a +type=wifi +interface-name=wlP1p1s0 + +[wifi] +mode=infrastructure +ssid=Sample-Wifi + +[wifi-security] +auth-alg=open +key-mgmt=wpa-psk +psk=REDACTED + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] diff --git a/bootc/pre/etc/NetworkManager/system-connections/.gitignore b/bootc/pre/etc/NetworkManager/system-connections/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/bootc/pre/etc/NetworkManager/system-connections/.gitignore @@ -0,0 +1 @@ +* diff --git a/bootc/pre/etc/NetworkManager/system-connections/Sample-Wifi.nmconnection b/bootc/pre/etc/NetworkManager/system-connections/Sample-Wifi.nmconnection new file mode 100644 index 0000000..8e12ace --- /dev/null +++ b/bootc/pre/etc/NetworkManager/system-connections/Sample-Wifi.nmconnection @@ -0,0 +1,23 @@ +[connection] +id=Sample-Wifi +uuid=e6b2f736-4787-43f2-866d-996ad025d95a +type=wifi +interface-name=wlP1p1s0 + +[wifi] +mode=infrastructure +ssid=Sample-Wifi + +[wifi-security] +auth-alg=open +key-mgmt=wpa-psk +psk=REDACTED + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] diff --git a/bootc/root/etc/containers/systemd/intelligent-train.container b/bootc/root/etc/containers/systemd/intelligent-train.container new file mode 100644 index 0000000..ec97c67 --- /dev/null +++ b/bootc/root/etc/containers/systemd/intelligent-train.container @@ -0,0 +1,23 @@ +[Unit] +Description=AI Auto-Pilot +After=local-fs.target + +[Service] +ExecStartPre=-podman network create --ignore app + +[Container] +ContainerName=intelligent-train +Image=quay.io/demo-ai-edge-crazy-train/intelligent-train:latest +Network=app +PublishPort=8080:8080 +EnvironmentFile=/etc/intelligent-train.env + +# Needed for Nvidia GPU Acceleration +PodmanArgs=--runtime /usr/bin/nvidia-container-runtime +GroupAdd=keep-groups +SecurityLabelDisable=true +Environment=NVIDIA_VISIBLE_DEVICES=nvidia.com/gpu=all + +[Install] +# Start by default on boot +WantedBy=multi-user.target default.target diff --git a/bootc/root/etc/containers/systemd/mosquitto.container b/bootc/root/etc/containers/systemd/mosquitto.container new file mode 100644 index 0000000..34eb550 --- /dev/null +++ b/bootc/root/etc/containers/systemd/mosquitto.container @@ -0,0 +1,20 @@ +[Unit] +Description=Mosquitto MQTT Broker +After=local-fs.target + +[Service] +ExecStartPre=-podman network create --ignore app + +[Container] +ContainerName=mosquitto +Image=docker.io/library/eclipse-mosquitto:latest +Network=app +PublishPort=1883:1883 +PublishPort=9001:9001 +Volume=/var/lib/mosquitto/data:/mosquitto/data:z +Volume=/var/lib/mosquitto/log:/mosquitto/log:z +Volume=/etc/mosquitto:/mosquitto/config:z + +[Install] +# Start by default on boot +WantedBy=multi-user.target default.target diff --git a/bootc/root/etc/intelligent-train.env b/bootc/root/etc/intelligent-train.env new file mode 100644 index 0000000..25a1d67 --- /dev/null +++ b/bootc/root/etc/intelligent-train.env @@ -0,0 +1,6 @@ +MQTT_BROKER=mosquitto +MQTT_PORT=1883 +MQTT_TOPIC=train-image +MQTT_PUB_TOPIC=train-model-result +MODEL_PATH=models/model.onnx +MIN_CONF_THRESHOLD=0.7 diff --git a/bootc/root/etc/mosquitto/mosquitto.conf b/bootc/root/etc/mosquitto/mosquitto.conf new file mode 100644 index 0000000..1a0864c --- /dev/null +++ b/bootc/root/etc/mosquitto/mosquitto.conf @@ -0,0 +1,7 @@ +user mosquitto +persistence true +persistence_location /mosquitto/data/ +listener 1883 0.0.0.0 +protocol mqtt +allow_anonymous true +log_dest file /mosquitto/log/mosquitto.log diff --git a/bootc/root/etc/motd.d/hello-world b/bootc/root/etc/motd.d/hello-world new file mode 100644 index 0000000..8ab686e --- /dev/null +++ b/bootc/root/etc/motd.d/hello-world @@ -0,0 +1 @@ +Hello, World! diff --git a/bootc/root/etc/systemd/system/nvidia-ctk-init.service b/bootc/root/etc/systemd/system/nvidia-ctk-init.service new file mode 100644 index 0000000..633bb12 --- /dev/null +++ b/bootc/root/etc/systemd/system/nvidia-ctk-init.service @@ -0,0 +1,15 @@ +[Unit] +Description=Run nvidia-ctk cdi generate +Wants=local-fs.target +After=local-fs.target +ConditionPathExists=!/etc/cdi/nvidia.yaml +ConditionPathExists=/usr/bin/nvidia-ctk +ConditionArchitecture=arm64 + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=nvidia-ctk cdi generate --output=/etc/cdi/nvidia + +[Install] +WantedBy=multi-user.target diff --git a/bootc/root/etc/systemd/system/repo-intelligent-train.service b/bootc/root/etc/systemd/system/repo-intelligent-train.service new file mode 100644 index 0000000..f6bfe25 --- /dev/null +++ b/bootc/root/etc/systemd/system/repo-intelligent-train.service @@ -0,0 +1,12 @@ +[Unit] +Description=Sync the intelligent-train git repo +Wants=network-online.target +After=network-online.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/sh -c 'if [ -d /root/intelligent-train ]; then cd /root/intelligent-train && git pull ; else git clone -b main https://github.com/Demo-AI-Edge-Crazy-Train/intelligent-train.git /root/intelligent-train ; fi' + +[Install] +WantedBy=multi-user.target diff --git a/bootc/root/etc/vconsole.conf b/bootc/root/etc/vconsole.conf new file mode 100644 index 0000000..f40c504 --- /dev/null +++ b/bootc/root/etc/vconsole.conf @@ -0,0 +1,2 @@ +KEYMAP="fr-oss" +FONT="eurlatgr" diff --git a/bootc/root/usr/lib/bootc/kargs.d/00-console.toml b/bootc/root/usr/lib/bootc/kargs.d/00-console.toml new file mode 100644 index 0000000..f28b5cc --- /dev/null +++ b/bootc/root/usr/lib/bootc/kargs.d/00-console.toml @@ -0,0 +1,2 @@ +kargs = ["console=tty0", "console=ttyS0"] +match-architectures = ["x86_64"] diff --git a/bootc/template-offline.ks b/bootc/template-offline.ks new file mode 100644 index 0000000..9165030 --- /dev/null +++ b/bootc/template-offline.ks @@ -0,0 +1,60 @@ +## +## Environment setup +## + +# Install mode: text (interactive installs) or cmdline (unattended installs) +text + +# French keyboard layout +keyboard --vckeymap=fr --xlayouts='fr' + +# English i18n +lang en_US.UTF-8 --addsupport fr_FR.UTF-8 + +# Accept the EULA +eula --agreed + +# Which action to perform after install: poweroff or reboot +reboot + +# Timezone is GMT +timezone Etc/GMT --utc + +## +## network configuration +## + +# THERE IS NOTHING HERE SINCE IT IS AN OFFLINE INSTALL + +## +## partitioning +## + +# Install on /dev/vda +#ignoredisk --only-use=vda + +# Install Grub in the MBR of /dev/vda +#bootloader --location=mbr --boot-drive=vda + +# Append kernel args to the boot command +bootloader --append="$KERNEL_CMDLINE" + +# Clear the target disk +zerombr + +# Remove existing partitions +clearpart --all --initlabel + +# Automatically create partitions required by hardware platform +reqpart --add-boot + +# Create a root and a /var partition +part / --fstype xfs --size=1 --grow --asprimary --label=root +#part /var --fstype xfs --size=1 --grow --asprimary --label=var + +## +## Installation +## + +rootpw --lock +ostreecontainer --url=/run/install/repo/container --transport=oci --no-signature-verification diff --git a/bootc/template-online.ks b/bootc/template-online.ks new file mode 100644 index 0000000..f83d045 --- /dev/null +++ b/bootc/template-online.ks @@ -0,0 +1,64 @@ +## +## Environment setup +## + +# Install mode: text (interactive installs) or cmdline (unattended installs) +text + +# French keyboard layout +keyboard --vckeymap=fr --xlayouts='fr' + +# English i18n +lang en_US.UTF-8 --addsupport fr_FR.UTF-8 + +# Accept the EULA +eula --agreed + +# Which action to perform after install: poweroff or reboot +reboot + +# Timezone is GMT +timezone Etc/GMT --utc + +## +## network configuration +## + +# Configure the first network device +network --bootproto=dhcp --device=enp1s0 --noipv6 --activate + +# Set the hostname +#network --hostname=localhost.localdomain + +## +## partitioning +## + +# Install on /dev/vda +#ignoredisk --only-use=vda + +# Install Grub in the MBR of /dev/vda +#bootloader --location=mbr --boot-drive=vda + +# Append kernel args to the boot command +bootloader --append="$KERNEL_CMDLINE" + +# Clear the target disk +zerombr + +# Remove existing partitions +clearpart --all --initlabel + +# Automatically create partitions required by hardware platform +reqpart --add-boot + +# Create a root and a /var partition +part / --fstype xfs --size=1 --grow --asprimary --label=root +#part /var --fstype xfs --size=1 --grow --asprimary --label=var + +## +## Installation +## + +rootpw --lock +ostreecontainer --url="$TARGET_IMAGE" --transport=registry --no-signature-verification diff --git a/bootc/test.sh b/bootc/test.sh new file mode 100755 index 0000000..0967d9f --- /dev/null +++ b/bootc/test.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +set -Eeuo pipefail + +# Source variables and environment +source ./env.sh + +# Constants +LOCAL_ARCH="$(arch)" +ARCH="${1:-$LOCAL_ARCH}" +TYPE="${2:-qcow2}" +DOMAIN_NAME="test-$NAME-$TYPE-$ARCH" + +# Cleanup +if virsh list --name | grep -Eq "^$DOMAIN_NAME\$"; then + virsh destroy "$DOMAIN_NAME" +fi +if virsh list --all --name | grep -Eq "^$DOMAIN_NAME\$"; then + virsh undefine "$DOMAIN_NAME" --nvram +fi +rm -rf "/var/lib/libvirt/images/$DOMAIN_NAME" +mkdir -p "/var/lib/libvirt/images/$DOMAIN_NAME" + +# Computing virt-install options +declare -a VIRT_INSTALL_OPTS=() +if [[ "$ARCH" != "$LOCAL_ARCH" ]]; then + VIRT_INSTALL_OPTS+=("--virt-type" "qemu" "--arch" "$ARCH") +else + VIRT_INSTALL_OPTS+=("--cpu" "host-passthrough") +fi +case "$TYPE" in +"qcow2") + cp "disk-$NAME-$ARCH.qcow2" "/var/lib/libvirt/images/$DOMAIN_NAME/disk.qcow2" + VIRT_INSTALL_OPTS+=("--disk" "path=/var/lib/libvirt/images/$DOMAIN_NAME/disk.qcow2,format=qcow2,bus=virtio,size=100" + "--import" + "--network" "network=default") + ;; +"kickstart") + cp "install-$NAME-$ARCH.iso" "/var/lib/libvirt/images/$DOMAIN_NAME/install.iso" + VIRT_INSTALL_OPTS+=("--disk" "path=/var/lib/libvirt/images/$DOMAIN_NAME/disk.qcow2,format=qcow2,bus=virtio,size=100" + "--location" "/var/lib/libvirt/images/$DOMAIN_NAME/install.iso,kernel=images/pxeboot/vmlinuz,initrd=images/pxeboot/initrd.img" + "--extra-args" "console=ttyS0 inst.ks=cdrom:/osbuild.ks" + "--network" "network=default") + ;; +"kickstart-online") + cp "install-$NAME-$ARCH-online.iso" "/var/lib/libvirt/images/$DOMAIN_NAME/install.iso" + VIRT_INSTALL_OPTS+=("--disk" "path=/var/lib/libvirt/images/$DOMAIN_NAME/disk.qcow2,format=qcow2,bus=virtio,size=100" + "--location" "/var/lib/libvirt/images/$DOMAIN_NAME/install.iso,kernel=images/pxeboot/vmlinuz,initrd=images/pxeboot/initrd.img" + "--extra-args" "console=ttyS0 inst.ks=cdrom:/osbuild.ks" + "--network" "network=default") + ;; +"kickstart-offline") + cp "install-$NAME-$ARCH-offline.iso" "/var/lib/libvirt/images/$DOMAIN_NAME/install.iso" + VIRT_INSTALL_OPTS+=("--disk" "path=/var/lib/libvirt/images/$DOMAIN_NAME/disk.qcow2,format=qcow2,bus=virtio,size=100" + "--location" "/var/lib/libvirt/images/$DOMAIN_NAME/install.iso,kernel=images/pxeboot/vmlinuz,initrd=images/pxeboot/initrd.img" + "--extra-args" "console=ttyS0 inst.ks=cdrom:/osbuild.ks" + "--network" "none") + ;; +*) + echo "Wrong artefact type $TYPE: expected either 'qcow2' or 'kickstart'." + exit 1 + ;; +esac + +# Boot VM +set -x +virt-install --name "$DOMAIN_NAME" --memory 4096 --vcpus 2 \ + --console pty,target_type=virtio --serial pty --graphics none \ + --os-variant rhel9-unknown --boot uefi \ + "${VIRT_INSTALL_OPTS[@]}"