From 5e300408981706f59e50f8f4af2eb23fd51c7034 Mon Sep 17 00:00:00 2001 From: Jika Date: Wed, 14 Jan 2026 17:59:45 +0100 Subject: [PATCH] First commit --- DECISIONS.md | 3 + README.md | 29 +++++++ ansible/README.md | 3 + installer/README.md | 27 +++++++ installer/patch-disk-config.sh | 72 +++++++++++++++++ installer/user_config_base.json | 133 ++++++++++++++++++++++++++++++++ installer/user_cred.json | 1 + 7 files changed, 268 insertions(+) create mode 100644 DECISIONS.md create mode 100644 README.md create mode 100644 ansible/README.md create mode 100644 installer/README.md create mode 100755 installer/patch-disk-config.sh create mode 100644 installer/user_config_base.json create mode 100644 installer/user_cred.json diff --git a/DECISIONS.md b/DECISIONS.md new file mode 100644 index 0000000..301cf85 --- /dev/null +++ b/DECISIONS.md @@ -0,0 +1,3 @@ +# DECISIONS + +This document some decisions made for the system setup diff --git a/README.md b/README.md new file mode 100644 index 0000000..da88eff --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# System specification + +The goal of this repository is to document and codify my system setup. + +This repository defines: +- how a system is bootstrapped +- which system packages and services are installed +- which system-level configuration is applied +- why certain decisions were made (when relevant) + +## Arch bootstrap + +After writing the [iso](https://archlinux.org/download/) file to a bootable media and booted on the device, archinstall can be used with the profile located in the `installer` directory. It will create the minimal setup for ansible to work on. + +Some helper: +```bash +loadkeys be-latin1 #load the belgian keyboard keys + +``` + +## Ansible replication + +## Personal config + +See dotfiles [repo]() + + + + diff --git a/ansible/README.md b/ansible/README.md new file mode 100644 index 0000000..2081d50 --- /dev/null +++ b/ansible/README.md @@ -0,0 +1,3 @@ +# Ansible + +Ansible is used to easily replicate most of the system diff --git a/installer/README.md b/installer/README.md new file mode 100644 index 0000000..9fdb04b --- /dev/null +++ b/installer/README.md @@ -0,0 +1,27 @@ +# Archinstall + +The goal of archinstall is to easily and reproducibly create a minimal arch install. + +Ansible is then used to do the heavy lifting. + +The `./patch-disk-config.sh` scripts goal is to help Host file transfer (QEMU user networking) + +When using QEMU user-mode networking (`10.0.2.0/24`), the host cannot reach the VM directly. +To transfer files from the VM to the host, use `nc`. + +On the host (receive): +```sh +nc -l -p 8001 > archinstall.json +```` + +On the VM (send): + +```sh +nc 10.0.2.2 8001 < /root/archinstall.json +``` + +`10.0.2.2` is the host address in QEMU user networking. + diff --git a/installer/patch-disk-config.sh b/installer/patch-disk-config.sh new file mode 100755 index 0000000..f650064 --- /dev/null +++ b/installer/patch-disk-config.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# This wrapper script dynamically adapts the archinstall configuration to the target machine. +# +# The target disk MUST be provided as a parameter (e.g. /dev/nvme0n1 or a +# /dev/disk/by-id/* path) +# +# This avoids hardcoding device names (e.g. /dev/sda, /dev/nvme0n1) and disk sizes, +# making the same archinstall config usable across multiple devices. + +# Usage: +# ./patch-disk-config.sh /dev/nvme0n1 + +set -euo pipefail + +CFG_IN="user_config_base.json" +CFG_OUT="user_config.json" +MIN_GIB=80 + +die() { echo "Error: $*" >&2; exit 1; } + +if [[ $# -ne 1 ]]; then + echo "Usage: $0 " + exit 1 +fi + +DISK="$1" + +# Basic validation +[[ -b "$DISK" ]] || die "'$DISK' is not a block device." + +# Refuse removable devices +[[ "$(lsblk -dn -o RM "$DISK")" == "0" ]] || die "'$DISK' is removable. Refusing." + +# Minimum size check (bytes) +SIZE_BYTES="$(lsblk -dn -o SIZE -b "$DISK")" +(( SIZE_BYTES >= MIN_GIB * 1024 * 1024 * 1024 )) || die "'$DISK' is smaller than ${MIN_GIB}GiB." + +# Sanity: ensure expected JSON structure exists +jq -e ' + .disk_config.device_modifications + | type == "array" and length >= 1 + and (. [0].partitions | type == "array" and length >= 2) + and (. [0].partitions[1].start.value | type == "number") + and (. [0].partitions[1].size.value | type == "number") +' "$CFG_IN" >/dev/null || die "Unexpected JSON structure in $CFG_IN (cannot locate partitions[1].start/size)." + +# Compute "root = remaining space" in bytes based on the configured root partition start offset +ROOT_START_BYTES="$(jq -r '.disk_config.device_modifications[0].partitions[1].start.value' "$CFG_IN")" +[[ "$ROOT_START_BYTES" =~ ^[0-9]+$ ]] || die "Root start offset is not a number: $ROOT_START_BYTES" + +ROOT_SIZE_BYTES=$(( SIZE_BYTES - ROOT_START_BYTES )) +(( ROOT_SIZE_BYTES > 0 )) || die "Computed root size is not positive. Disk may be smaller than the configured start offset." + +# Patch: +# - set target disk +# - set root partition size to fill to end of disk (bytes) +jq --arg d "$DISK" --argjson root_size "$ROOT_SIZE_BYTES" ' + .disk_config.device_modifications[0].device = $d + | .disk_config.device_modifications[0].partitions[1].size.unit = "B" + | .disk_config.device_modifications[0].partitions[1].size.value = $root_size +' "$CFG_IN" > "$CFG_OUT" + +# Report +BOOT_SIZE_UNIT="$(jq -r '.disk_config.device_modifications[0].partitions[0].size.unit' "$CFG_OUT")" +BOOT_SIZE_VALUE="$(jq -r '.disk_config.device_modifications[0].partitions[0].size.value' "$CFG_OUT")" + +echo "Prepared archinstall config: $CFG_OUT" +echo " Disk : $DISK" +echo " Disk bytes : $SIZE_BYTES" +echo " /boot size : ${BOOT_SIZE_VALUE}${BOOT_SIZE_UNIT}" +echo " Root start : $ROOT_START_BYTES B" +echo " Root size : $ROOT_SIZE_BYTES B (fills remaining space)" diff --git a/installer/user_config_base.json b/installer/user_config_base.json new file mode 100644 index 0000000..a56fdb8 --- /dev/null +++ b/installer/user_config_base.json @@ -0,0 +1,133 @@ +{ + "app_config": {}, + "archinstall-language": "English", + "auth_config": {}, + "bootloader_config": { + "bootloader": "Grub", + "removable": false, + "uki": false + }, + "custom_commands": [], + "disk_config": { + "btrfs_options": { + "snapshot_config": { + "type": "Snapper" + } + }, + "config_type": "default_layout", + "device_modifications": [ + { + "device": "/dev/vda", + "partitions": [ + { + "btrfs": [], + "dev_path": null, + "flags": [ + "boot" + ], + "fs_type": "fat32", + "mount_options": [], + "mountpoint": "/boot", + "obj_id": "66709eb4-7172-4edd-b2ea-add010dad2ea", + "size": { + "sector_size": { + "unit": "B", + "value": 512 + }, + "unit": "GiB", + "value": 1 + }, + "start": { + "sector_size": { + "unit": "B", + "value": 512 + }, + "unit": "MiB", + "value": 1 + }, + "status": "create", + "type": "primary" + }, + { + "btrfs": [ + { + "mountpoint": "/", + "name": "@" + }, + { + "mountpoint": "/home", + "name": "@home" + }, + { + "mountpoint": "/var/log", + "name": "@log" + }, + { + "mountpoint": "/var/cache/pacman/pkg", + "name": "@pkg" + } + ], + "dev_path": null, + "flags": [], + "fs_type": "btrfs", + "mount_options": [], + "mountpoint": null, + "obj_id": "596c1c52-a12a-4015-9b1b-86483e57174c", + "size": { + "sector_size": { + "unit": "B", + "value": 512 + }, + "unit": "B", + "value": 63349719040 + }, + "start": { + "sector_size": { + "unit": "B", + "value": 512 + }, + "unit": "B", + "value": 1074790400 + }, + "status": "create", + "type": "primary" + } + ], + "wipe": true + } + ], + "disk_encryption": { + "encryption_type": "luks", + "lvm_volumes": [], + "partitions": [ + "596c1c52-a12a-4015-9b1b-86483e57174c" + ] + } + }, + "hostname": "archlinux", + "kernels": [ + "linux" + ], + "locale_config": { + "kb_layout": "be-latin1", + "sys_enc": "UTF-8", + "sys_lang": "en_US.UTF-8" + }, + "network_config": { + "type": "nm" + }, + "ntp": true, + "packages": [ + "git", + "ansible-core" + ], + "parallel_downloads": 0, + "script": null, + "services": [], + "swap": { + "algorithm": "zstd", + "enabled": true + }, + "timezone": "Europe/Brussels", + "version": "3.0.15" +} diff --git a/installer/user_cred.json b/installer/user_cred.json new file mode 100644 index 0000000..08c2d8c --- /dev/null +++ b/installer/user_cred.json @@ -0,0 +1 @@ +$argon2id$rqnG-ofpluTBwMEUy7pV3w==$Z0FBQUFBQnBaOHM3eTR6WkVlZ3RUX2JPakZycXNIdFJHN0lQMGxLeDRaUmRJdVRZbkZZOFhHdnpYbHBQUmxMQUNSTUNYWGxaczROaTktMGNXbklHcklWWmY2TnJRMUlxazZmZFE0UGN2V2Vud0VkQmY5RE5nMjRPeVdGclBMNEItNjRLMjFQTjdUeTRXZTJEZ3NtdGNxTEE4dXZDZklkbXZ3Y1hTWGQ4eFpFeVJuODFDUWMybW5wYlB3RlcwTGQxWFp3UThYN0lPQkJRXzBEX1loSUNHekdJOEtRc3N3T1FRWUY1T3B1cTRvd0lUaHlSblVJaDNhVVZGejFLLTd6ckRnZkxkaVE3TnAwUGdIaGRYNVZWYWY3WElGaTVWZm5QalpnWG0tdEdILThRQXBYdUc0RVJKQjA3cDVrZmNaM3RPQUVEZFdEX3lpdTZoNkxVRXRMMkZuYjdxaTM3a2lkbGpZbWV1MEs0c2RwWG9qcGcySDRPNDNUWHpSaFRXTUlpM2wzUFRJQnNHZFFSbm9YOEJpNTZIVXFXTHp6Z3ZNd05ZUVRsUDFqOVpqbmFIV3hjZVdXWFBaVnBiRWVJcndMTF9Hd1MtQ3paQm1Xa01DWGFGMnNOM3dDdnl2WW40MTB5bERwd0pKM0pUU2dkMllsTGxZX3lHRjlfUWFzLXBKMzdmeWsyQUFpQXQzaEo4MWlWMjZmMzRhX3lDalh3M21rU1BQNWhUaXU4dU0wdWdTV2pLVjVYbTJvZUdfUVkwT2QzakZXQXNGTzdodFhp \ No newline at end of file