200 lines
7.9 KiB
Bash
200 lines
7.9 KiB
Bash
#!/usr/bin/env bash
|
||
# ─────────────────────────────────────────────────────────────
|
||
# Nexus One AI — Starter Tier ISO Builder
|
||
# Hardware target: compact workstation (1× RTX 5090, 64 GB RAM, 2 TB NVMe)
|
||
#
|
||
# Usage:
|
||
# cd ~/aipackage
|
||
# bash autoinstall/build-iso-starter.sh
|
||
#
|
||
# Output: autoinstall/cezen-ai-starter-ubuntu2204.iso
|
||
# Flash to USB:
|
||
# diskutil unmountDisk /dev/diskN
|
||
# sudo dd if=cezen-ai-starter-ubuntu2204.iso of=/dev/diskN bs=4m status=progress
|
||
# ─────────────────────────────────────────────────────────────
|
||
set -e
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PACKAGE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||
WORK_DIR="/tmp/cezen-iso-starter-work"
|
||
ORIGINAL_ISO="/tmp/ubuntu-22.04.5-live-server-amd64.iso"
|
||
OUTPUT_ISO="$SCRIPT_DIR/cezen-ai-starter-ubuntu2204.iso"
|
||
UBUNTU_URL="https://releases.ubuntu.com/22.04.5/ubuntu-22.04.5-live-server-amd64.iso"
|
||
TIER="starter"
|
||
|
||
echo "╔══════════════════════════════════════════════════════╗"
|
||
echo "║ Nexus One AI — ISO Builder [STARTER TIER] ║"
|
||
echo "║ RTX 5090 · 64 GB RAM · 2 TB NVMe · 1–5 users ║"
|
||
echo "╚══════════════════════════════════════════════════════╝"
|
||
echo ""
|
||
|
||
# ── Install build tools ────────────────────────
|
||
echo "→ Installing build tools..."
|
||
apt-get update -qq
|
||
apt-get install -y -qq xorriso wget isolinux rsync
|
||
echo "✓ Tools ready"
|
||
|
||
# ── Download Ubuntu ISO ────────────────────────
|
||
if [ -f "$ORIGINAL_ISO" ]; then
|
||
echo "✓ Ubuntu ISO already downloaded"
|
||
else
|
||
echo "→ Downloading Ubuntu 22.04.5 Server ISO (~1.8 GB)..."
|
||
wget --show-progress -O "$ORIGINAL_ISO" "$UBUNTU_URL"
|
||
echo "✓ Downloaded"
|
||
fi
|
||
|
||
# ── Extract ISO ────────────────────────────────
|
||
echo "→ Extracting ISO..."
|
||
rm -rf "$WORK_DIR"
|
||
mkdir -p "$WORK_DIR"
|
||
xorriso -osirrox on \
|
||
-indev "$ORIGINAL_ISO" \
|
||
-extract / "$WORK_DIR" 2>/dev/null
|
||
chmod -R u+w "$WORK_DIR"
|
||
echo "✓ Extracted"
|
||
|
||
# ── Inject Starter autoinstall files ──────────
|
||
echo "→ Injecting Starter autoinstall config..."
|
||
mkdir -p "$WORK_DIR/nocloud"
|
||
cp "$SCRIPT_DIR/user-data-starter" "$WORK_DIR/nocloud/user-data"
|
||
cp "$SCRIPT_DIR/meta-data" "$WORK_DIR/nocloud/meta-data"
|
||
echo "✓ user-data-starter and meta-data injected"
|
||
|
||
# ── Online installer mode ──────────────────────
|
||
# The installed system pulls the current package from cgit on first boot. This
|
||
# keeps the ISO small and avoids shipping stale backend/portal code.
|
||
echo "✓ Online installer mode: package will be pulled from cgit on first boot"
|
||
|
||
# ── Patch GRUB ────────────────────────────────
|
||
echo "→ Patching GRUB config..."
|
||
GRUB_CFG="$WORK_DIR/boot/grub/grub.cfg"
|
||
cp "$GRUB_CFG" "$GRUB_CFG.orig"
|
||
|
||
sed -i "s/set timeout=.*/set timeout=5/" "$GRUB_CFG"
|
||
sed -i "s/set timeout_style=.*/set timeout_style=countdown/" "$GRUB_CFG"
|
||
sed -i '/^\s*linux.*vmlinuz/s|---|autoinstall ds=nocloud\\;s=/cdrom/nocloud/ ---|' "$GRUB_CFG"
|
||
|
||
# Update GRUB title to reflect Starter tier
|
||
sed -i 's/Install Ubuntu Server/Install Nexus One AI — Starter Tier/' "$GRUB_CFG" || true
|
||
echo "✓ GRUB patched"
|
||
|
||
# ── Extract MBR and EFI boot data ─────────────
|
||
echo "→ Extracting boot data from original ISO..."
|
||
MBR_TEMPLATE=$(mktemp)
|
||
EFI_IMG=$(mktemp)
|
||
dd if="$ORIGINAL_ISO" bs=1 count=432 of="$MBR_TEMPLATE" 2>/dev/null
|
||
|
||
EFI_LINE=$(fdisk -l "$ORIGINAL_ISO" 2>/dev/null | grep "EFI")
|
||
echo " EFI partition info: $EFI_LINE"
|
||
EFI_START=$(echo "$EFI_LINE" | awk '{print $2}')
|
||
EFI_SIZE=$(echo "$EFI_LINE" | awk '{print $4}')
|
||
|
||
if [ -z "$EFI_START" ] || [ -z "$EFI_SIZE" ]; then
|
||
echo "ERROR: Could not detect EFI partition in ISO."
|
||
echo "Run: fdisk -l $ORIGINAL_ISO"
|
||
exit 1
|
||
fi
|
||
|
||
dd if="$ORIGINAL_ISO" bs=512 skip="$EFI_START" count="$EFI_SIZE" \
|
||
of="$EFI_IMG" 2>/dev/null
|
||
echo "✓ EFI partition extracted (start=$EFI_START, size=$EFI_SIZE)"
|
||
|
||
# ── Repack ISO (pass 1) ────────────────────────
|
||
echo "→ Repacking ISO (pass 1)..."
|
||
xorriso -as mkisofs \
|
||
-r \
|
||
-V "CezenAI_Starter_2204" \
|
||
-o "$OUTPUT_ISO" \
|
||
--grub2-mbr "$MBR_TEMPLATE" \
|
||
-partition_offset 16 \
|
||
--mbr-force-bootable \
|
||
-append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b "$EFI_IMG" \
|
||
-appended_part_as_gpt \
|
||
-iso_mbr_part_type a2a0d0ebe5b9334487c068b6b72699c7 \
|
||
-c "/boot.catalog" \
|
||
-b "/boot/grub/i386-pc/eltorito.img" \
|
||
-no-emul-boot \
|
||
-boot-load-size 4 \
|
||
-boot-info-table \
|
||
--grub2-boot-info \
|
||
-eltorito-alt-boot \
|
||
-e "--interval:appended_partition_2:::" \
|
||
-no-emul-boot \
|
||
"$WORK_DIR"
|
||
|
||
# ── Refresh md5sum.txt and repack (pass 2) ────
|
||
echo "→ Refreshing md5sum.txt..."
|
||
FINAL_DIR=$(mktemp -d)
|
||
VERIFY_DIR=$(mktemp -d)
|
||
trap 'rm -rf "$WORK_DIR" "$MBR_TEMPLATE" "$EFI_IMG" "$FINAL_DIR" "$VERIFY_DIR"' EXIT
|
||
|
||
xorriso -osirrox on -indev "$OUTPUT_ISO" -extract / "$FINAL_DIR" >/dev/null 2>&1
|
||
chmod -R u+w "$FINAL_DIR"
|
||
(
|
||
cd "$FINAL_DIR"
|
||
rm -f md5sum.txt
|
||
find . -type f \
|
||
! -path './md5sum.txt' \
|
||
! -path './boot.catalog' \
|
||
-print0 \
|
||
| sort -z \
|
||
| xargs -0 md5sum > md5sum.txt
|
||
)
|
||
echo "✓ md5sum.txt refreshed"
|
||
|
||
echo "→ Repacking ISO (pass 2)..."
|
||
xorriso -as mkisofs \
|
||
-r \
|
||
-V "CezenAI_Starter_2204" \
|
||
-o "$OUTPUT_ISO" \
|
||
--grub2-mbr "$MBR_TEMPLATE" \
|
||
-partition_offset 16 \
|
||
--mbr-force-bootable \
|
||
-append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b "$EFI_IMG" \
|
||
-appended_part_as_gpt \
|
||
-iso_mbr_part_type a2a0d0ebe5b9334487c068b6b72699c7 \
|
||
-c "/boot.catalog" \
|
||
-b "/boot/grub/i386-pc/eltorito.img" \
|
||
-no-emul-boot \
|
||
-boot-load-size 4 \
|
||
-boot-info-table \
|
||
--grub2-boot-info \
|
||
-eltorito-alt-boot \
|
||
-e "--interval:appended_partition_2:::" \
|
||
-no-emul-boot \
|
||
"$FINAL_DIR"
|
||
|
||
# ── Verify output ISO ──────────────────────────
|
||
echo "→ Verifying rebuilt ISO manifest..."
|
||
xorriso -osirrox on -indev "$OUTPUT_ISO" -extract / "$VERIFY_DIR" >/dev/null 2>&1
|
||
chmod -R u+w "$VERIFY_DIR"
|
||
(
|
||
cd "$VERIFY_DIR"
|
||
md5sum -c md5sum.txt >/tmp/cezen-iso-md5check-starter.log 2>&1 || {
|
||
echo "ERROR: Rebuilt ISO failed its own md5sum.txt verification."
|
||
sed -n '1,40p' /tmp/cezen-iso-md5check-starter.log
|
||
exit 1
|
||
}
|
||
)
|
||
echo "✓ Output ISO manifest verified"
|
||
|
||
echo ""
|
||
echo "╔══════════════════════════════════════════════════════╗"
|
||
echo "║ Done! Starter Tier ISO ready. ║"
|
||
echo "╚══════════════════════════════════════════════════════╝"
|
||
echo ""
|
||
ls -lh "$OUTPUT_ISO"
|
||
echo ""
|
||
echo "→ Transfer to MacBook:"
|
||
echo " scp user@server:~/aipackage/autoinstall/cezen-ai-starter-ubuntu2204.iso ."
|
||
echo ""
|
||
echo "→ Flash to USB (macOS):"
|
||
echo " diskutil list # find USB e.g. /dev/disk4"
|
||
echo " diskutil unmountDisk /dev/disk4"
|
||
echo " sudo dd if=cezen-ai-starter-ubuntu2204.iso of=/dev/disk4 bs=4m status=progress"
|
||
echo ""
|
||
echo "→ Post-flash: boot the workstation from USB."
|
||
echo " Unattended install completes in ~10 min."
|
||
echo " First-boot wizard runs on tty1 — set IP, org name, admin password."
|
||
echo " Then run: sudo bash /opt/aipackage/install.sh --tier starter"
|