feat(ci): installer ISO workflow (v0.7 ostreecontainer path)
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.
This commit is contained in:
parent
266090ea0d
commit
9a087ae0da
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