feat(ci): installer ISO workflow (v0.7 ostreecontainer path)
Some checks failed
Build veilor-os Installer ISO / Build installer ISO (push) Failing after 49s
Some checks failed
Build veilor-os Installer ISO / Build installer ISO (push) Failing after 49s
Add livemedia-creator --make-iso pipeline that produces a small Anaconda installer ISO consuming a CI-buildable variant of the runtime ostreecontainer kickstart. Disk/LUKS/user blocks dropped from the CI ks (Anaconda interactive handles them); ostreecontainer URL pinned to ghcr.io/veilor-org/veilor-os:43. Output split into 1900M chunks; published to Forgejo installer-latest rolling tag. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
fe6042468b
commit
a0b0da3cf1
2 changed files with 210 additions and 0 deletions
163
.github/workflows/build-installer-iso.yml
vendored
Normal file
163
.github/workflows/build-installer-iso.yml
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
name: Build veilor-os Installer ISO
|
||||||
|
|
||||||
|
# v0.7+ — produces a small Anaconda installer ISO that consumes
|
||||||
|
# kickstart/install-ostreecontainer-installer.ks. The ISO boots
|
||||||
|
# Anaconda, asks for LUKS pw + admin pw interactively, then
|
||||||
|
# `ostreecontainer` populates / from the v0.7 OCI image at
|
||||||
|
# ghcr.io/veilor-org/veilor-os:43.
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [v0.7-bluebuild-spike]
|
||||||
|
paths:
|
||||||
|
- 'kickstart/install-ostreecontainer.ks'
|
||||||
|
- 'kickstart/install-ostreecontainer-installer.ks'
|
||||||
|
- 'bluebuild/recipe.yml'
|
||||||
|
- '.github/workflows/build-installer-iso.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
releasever:
|
||||||
|
description: 'Fedora release version'
|
||||||
|
required: false
|
||||||
|
default: '43'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write # needed to create+update installer-latest release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build installer ISO
|
||||||
|
runs-on: nullstone
|
||||||
|
timeout-minutes: 120
|
||||||
|
|
||||||
|
env:
|
||||||
|
RELEASEVER: ${{ github.event.inputs.releasever || '43' }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
|
- name: Install build tooling (Fedora)
|
||||||
|
run: |
|
||||||
|
set -euxo pipefail
|
||||||
|
dnf -y upgrade --refresh
|
||||||
|
dnf -y install --skip-unavailable \
|
||||||
|
lorax \
|
||||||
|
pykickstart \
|
||||||
|
anaconda-tui \
|
||||||
|
syslinux \
|
||||||
|
xorriso \
|
||||||
|
grub2-efi-x64 \
|
||||||
|
grub2-efi-x64-modules \
|
||||||
|
grub2-pc \
|
||||||
|
grub2-pc-modules \
|
||||||
|
shim-x64 \
|
||||||
|
efibootmgr
|
||||||
|
|
||||||
|
- name: Validate installer kickstart
|
||||||
|
run: |
|
||||||
|
set -euxo pipefail
|
||||||
|
ksvalidator kickstart/install-ostreecontainer-installer.ks
|
||||||
|
|
||||||
|
- name: Build installer ISO with livemedia-creator
|
||||||
|
run: |
|
||||||
|
set -euxo pipefail
|
||||||
|
mkdir -p build/out /var/lmc
|
||||||
|
ln -sfn "$GITHUB_WORKSPACE" /work
|
||||||
|
livemedia-creator \
|
||||||
|
--make-iso \
|
||||||
|
--no-virt \
|
||||||
|
--ks kickstart/install-ostreecontainer-installer.ks \
|
||||||
|
--resultdir build/out \
|
||||||
|
--tmp /var/lmc \
|
||||||
|
--title "veilor-os" \
|
||||||
|
--project "veilor-os" \
|
||||||
|
--releasever "$RELEASEVER" \
|
||||||
|
--logfile build/out/build.log \
|
||||||
|
2>&1 | tee -a build/out/build.log
|
||||||
|
|
||||||
|
- name: Rename ISO + sha256
|
||||||
|
run: |
|
||||||
|
set -euxo pipefail
|
||||||
|
ISO_FILE=$(ls build/out/*.iso 2>/dev/null | head -1)
|
||||||
|
[ -n "$ISO_FILE" ] || { echo "[ERR] no ISO produced"; exit 1; }
|
||||||
|
ISO_NAME="veilor-os-installer-${RELEASEVER}-$(date +%Y%m%d-%H%M%S).iso"
|
||||||
|
mv "$ISO_FILE" "build/out/$ISO_NAME"
|
||||||
|
cd build/out
|
||||||
|
sha256sum "$ISO_NAME" > "$ISO_NAME.sha256"
|
||||||
|
ls -lh "$ISO_NAME"
|
||||||
|
|
||||||
|
- name: Split ISO into 1900M chunks
|
||||||
|
if: success() && github.ref == 'refs/heads/v0.7-bluebuild-spike'
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cd build/out
|
||||||
|
ISO=$(ls *.iso | head -1)
|
||||||
|
[ -n "$ISO" ] || { echo "[ERR] no ISO"; exit 1; }
|
||||||
|
split -b 1900M -d --suffix-length=2 "$ISO" "${ISO}.part-"
|
||||||
|
rm -f "$ISO"
|
||||||
|
sha256sum *.part-* > "${ISO}.parts.sha256"
|
||||||
|
ls "${ISO}".part-*
|
||||||
|
|
||||||
|
- name: Publish to installer-latest rolling prerelease (Forgejo)
|
||||||
|
if: success() && github.ref == 'refs/heads/v0.7-bluebuild-spike' && github.server_url != 'https://github.com'
|
||||||
|
env:
|
||||||
|
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
FORGEJO_API: ${{ github.server_url }}/api/v1
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
GIT_SHA: ${{ github.sha }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
TAG="installer-latest"
|
||||||
|
REL_JSON=$(curl -fsSL -H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||||
|
"${FORGEJO_API}/repos/${REPO}/releases/tags/${TAG}" 2>/dev/null || echo "")
|
||||||
|
if [ -n "$REL_JSON" ]; then
|
||||||
|
REL_ID=$(echo "$REL_JSON" | grep -oE '"id":\s*[0-9]+' | head -1 | grep -oE '[0-9]+')
|
||||||
|
if [ -n "$REL_ID" ]; then
|
||||||
|
curl -fsSL -X DELETE -H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||||
|
"${FORGEJO_API}/repos/${REPO}/releases/${REL_ID}" || true
|
||||||
|
curl -fsSL -X DELETE -H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||||
|
"${FORGEJO_API}/repos/${REPO}/git/refs/tags/${TAG}" || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
BODY="Rolling auto-build from v0.7-bluebuild-spike. Latest commit: ${GIT_SHA}.
|
||||||
|
|
||||||
|
Installer ISO — boots Anaconda, prompts for LUKS pw + admin pw,
|
||||||
|
then ostreecontainer-pulls / from ghcr.io/veilor-org/veilor-os:43.
|
||||||
|
|
||||||
|
Reassemble:
|
||||||
|
cat veilor-os-installer-*.iso.part-* > veilor-os-installer.iso
|
||||||
|
sha256sum -c veilor-os-installer-*.iso.parts.sha256
|
||||||
|
|
||||||
|
Not a stable release — for testing only."
|
||||||
|
PAYLOAD=$(BODY="$BODY" TAG="$TAG" python3 -c "
|
||||||
|
import json,os
|
||||||
|
print(json.dumps({
|
||||||
|
'tag_name': os.environ['TAG'],
|
||||||
|
'target_commitish': 'v0.7-bluebuild-spike',
|
||||||
|
'name': 'installer-latest (auto)',
|
||||||
|
'body': os.environ['BODY'],
|
||||||
|
'prerelease': True,
|
||||||
|
'draft': False,
|
||||||
|
}))")
|
||||||
|
REL_ID=$(curl -fsSL -X POST -H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$PAYLOAD" \
|
||||||
|
"${FORGEJO_API}/repos/${REPO}/releases" | \
|
||||||
|
grep -oE '"id":\s*[0-9]+' | head -1 | grep -oE '[0-9]+')
|
||||||
|
[ -n "$REL_ID" ] || { echo "[ERR] failed to create release"; exit 1; }
|
||||||
|
cd build/out
|
||||||
|
for f in *.iso.part-* *.sha256; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
curl -fsSL -X POST -H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||||
|
-F "attachment=@${f}" \
|
||||||
|
"${FORGEJO_API}/repos/${REPO}/releases/${REL_ID}/assets?name=${f}"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Print build log on failure
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
echo "─── build/out/build.log ───"
|
||||||
|
tail -200 build/out/build.log 2>/dev/null || echo "(no build.log)"
|
||||||
|
find build/out -name 'program.log' -exec tail -100 {} \; 2>/dev/null || true
|
||||||
|
find /var/lmc -name '*.log' -exec tail -50 {} \; 2>/dev/null || true
|
||||||
47
kickstart/install-ostreecontainer-installer.ks
Normal file
47
kickstart/install-ostreecontainer-installer.ks
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# veilor-os installer kickstart — v0.7 CI build variant
|
||||||
|
#
|
||||||
|
# Derived from kickstart/install-ostreecontainer.ks by stripping all
|
||||||
|
# __PLACEHOLDER__ tokens that the runtime gum TUI substitutes at install
|
||||||
|
# time. Anaconda's interactive TUI handles disk selection, LUKS passphrase,
|
||||||
|
# and user account creation in their place.
|
||||||
|
#
|
||||||
|
# Consumed by livemedia-creator --make-iso to produce
|
||||||
|
# veilor-os-installer-43-*.iso. Do NOT add __PLACEHOLDER__ tokens here —
|
||||||
|
# they cannot be filled at build time. See install-ostreecontainer.ks
|
||||||
|
# for the runtime template the gum TUI fills in.
|
||||||
|
|
||||||
|
# ── Locale / keyboard / time ──
|
||||||
|
keyboard --xlayouts='us'
|
||||||
|
lang en_US.UTF-8
|
||||||
|
timezone Europe/London --utc
|
||||||
|
|
||||||
|
# ── Install mode ──
|
||||||
|
text
|
||||||
|
firstboot --disable
|
||||||
|
eula --agreed
|
||||||
|
selinux --enforcing
|
||||||
|
|
||||||
|
# ── Network ──
|
||||||
|
network --bootproto=dhcp --device=link --activate --hostname=veilor-install
|
||||||
|
firewall --enabled --service=ssh
|
||||||
|
|
||||||
|
# ── Identity ──
|
||||||
|
# rootpw --lock only. No user directive — Anaconda's user spoke handles
|
||||||
|
# admin account creation interactively. Runtime ks substitutes
|
||||||
|
# --password=__ADMIN_PW__ for unattended installs.
|
||||||
|
rootpw --lock
|
||||||
|
|
||||||
|
# ── Disk / partitioning ──
|
||||||
|
# Intentionally absent. Anaconda's disk spoke presents interactive
|
||||||
|
# disk + LUKS + btrfs selection. Runtime ks (gum TUI) provides the
|
||||||
|
# full partition spec at real-install time.
|
||||||
|
|
||||||
|
# ── ostreecontainer: populate / from veilor-os OCI ──
|
||||||
|
ostreecontainer --url=ghcr.io/veilor-org/veilor-os:43 --transport=registry
|
||||||
|
|
||||||
|
# ── %post (chroot) ──
|
||||||
|
%post
|
||||||
|
set -uo pipefail
|
||||||
|
echo veilor-install > /etc/hostname
|
||||||
|
chage -d 0 admin 2>/dev/null || true
|
||||||
|
%end
|
||||||
Loading…
Reference in a new issue