1
0
Fork 0
mirror of https://github.com/JasonN3/build-container-installer.git synced 2025-12-25 10:57:55 +01:00

Merge branch 'main' into add_secure_boot

This commit is contained in:
Jason N 2024-03-18 14:36:32 -04:00 committed by GitHub
commit ec0cd1e6ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 1231 additions and 171 deletions

5
.dockerignore Normal file
View file

@ -0,0 +1,5 @@
.devcontainer
.github
.gitignore
action.yml
Containerfile

34
.github/workflows/bot_run_tests.yml vendored Normal file
View file

@ -0,0 +1,34 @@
name: Run tests on PR
on: issue_comment
jobs:
pr_commented:
name: Check Permissions
if: >
github.event.issue.pull_request &&
contains(github.event.comment.body, '/run tests')
runs-on: ubuntu-latest
steps:
- name: Check association
run: |
allowed=("OWNER" "COLLABORATOR")
value="\<${{ github.event.issue.author_association }}\>"
if [[ ${allowed[@]} =~ $value ]]
then
exit 0
else
exit 1
fi
run-tests:
name: Run Tests
permissions:
contents: read
packages: write
statuses: write
needs:
- pr_commented
uses: ./.github/workflows/build-and-test.yml
with:
pr: ${{ github.event.issue.number }}

View file

@ -1,4 +1,4 @@
name: Create and publish an ISO name: Tests
on: on:
push: push:
@ -6,26 +6,83 @@ on:
- 'main' - 'main'
tags: tags:
- 'v*' - 'v*'
pull_request: pull_request:
workflow_call:
inputs:
pr:
required: true
type: string
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
# Test Values # Test Values
env: env:
ARCH: 'x86_64' ARCH: 'x86_64'
IMAGE_NAME: 'base' IMAGE_NAME: 'base'
IMAGE_REPO: 'quay.io/fedora-ostree-desktops' IMAGE_REPO: 'quay.io/fedora-ostree-desktops'
VERSION: '39' IMAGE_TAG: '39'
VARIANT: 'Server' VARIANT: 'Server'
FLATPAK_REMOTE_REFS_DIR: flatpak_refs
SECURE_BOOT_KEY_URL: 'https://github.com/ublue-os/akmods/raw/main/certs/public_key.der' SECURE_BOOT_KEY_URL: 'https://github.com/ublue-os/akmods/raw/main/certs/public_key.der'
ENROLLMENT_PASSWORD: 'container-installer' ENROLLMENT_PASSWORD: 'container-installer'
jobs: jobs:
build-container: build-container:
if: >
github.event_name == 'push' ||
github.event_name == 'issue_comment' ||
( github.event_name == 'pull_request' &&
contains(github.event.pull_request.labels.*.name, 'auto-test') )
name: Build Container Image
env:
JOB_NAME: Build Container Image
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: write-all permissions:
contents: read
packages: write
statuses: write
steps: steps:
- name: Checkout repo - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
fetch-tags: 'true'
- name: Switch branch
if: inputs.pr
env:
GITHUB_USER: ${{ github.actor }}
GITHUB_TOKEN: ${{ github.token }}
run: |
sudo apt-get update
sudo apt-get install -y hub
hub pr checkout ${{ inputs.pr }}
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_ENV
- name: Get Current Job Log URL
if: inputs.pr && always()
uses: Tiryoh/gha-jobid-action@v1
id: jobs
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
job_name: "Run Tests / ${{ env.JOB_NAME }}"
- name: Set status
if: inputs.pr && always()
uses: myrotvorets/set-commit-status-action@v2.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
context: ${{ env.JOB_NAME }}
sha: ${{ env.sha }}
targetUrl: ${{ steps.jobs.outputs.html_url }}
- name: Docker meta - name: Docker meta
id: meta id: meta
@ -55,17 +112,73 @@ jobs:
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ github.token }} password: ${{ github.token }}
- name: Set status
if: inputs.pr && always()
uses: myrotvorets/set-commit-status-action@v2.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
context: ${{ env.JOB_NAME }}
sha: ${{ env.sha }}
targetUrl: ${{ steps.jobs.outputs.html_url }}
build-and-push-iso: build-and-push-iso:
name: Build ISO
env:
JOB_NAME: Build ISO
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:
- build-container - build-container
permissions: permissions:
contents: read contents: read
packages: write packages: write
statuses: write
continue-on-error: false
strategy:
fail-fast: false
matrix:
version:
- 38
- 39
- 40
outputs:
iso_name-38: ${{ steps.save_output.outputs.iso_name-38 }}
iso_name-39: ${{ steps.save_output.outputs.iso_name-39 }}
iso_name-40: ${{ steps.save_output.outputs.iso_name-40 }}
steps: steps:
- name: Checkout repo - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
submodules: recursive
- name: Switch branch
if: inputs.pr
env:
GITHUB_USER: ${{ github.actor }}
GITHUB_TOKEN: ${{ github.token }}
run: |
sudo apt-get update
sudo apt-get install -y hub
hub pr checkout ${{ inputs.pr }}
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_ENV
- name: Get Current Job Log URL
if: inputs.pr && always()
uses: Tiryoh/gha-jobid-action@v1
id: jobs
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
job_name: "Run Tests / ${{ env.JOB_NAME }}"
- name: Set status
if: inputs.pr && always()
uses: myrotvorets/set-commit-status-action@v2.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
context: ${{ env.JOB_NAME }}
sha: ${{ env.sha }}
targetUrl: ${{ steps.jobs.outputs.html_url }}
- name: Lowercase Registry - name: Lowercase Registry
id: registry_case id: registry_case
@ -83,23 +196,296 @@ jobs:
- name: Build ISO - name: Build ISO
uses: ./ uses: ./
id: build
with: with:
arch: ${{ env.ARCH}} arch: ${{ env.ARCH}}
image_name: ${{ env.IMAGE_NAME}} image_name: ${{ env.IMAGE_NAME}}
image_repo: ${{ env.IMAGE_REPO}} image_repo: ${{ env.IMAGE_REPO}}
version: ${{ env.VERSION }} image_tag: ${{ matrix.version }}
version: ${{ matrix.version }}
variant: ${{ env.VARIANT }} variant: ${{ env.VARIANT }}
flatpak_remote_refs_dir: /github/workspace/${{ env.FLATPAK_REMOTE_REFS_DIR }}
secure_boot_key_url: ${{ env.SECURE_BOOT_KEY_URL }}
enrollment_password: ${{ env.ENROLLMENT_PASSWORD }}
iso_name: ${{ env.IMAGE_NAME }}-${{ matrix.version }}-${{ github.event.pull_request.number || github.ref }}.iso
- name: Rename ISO - name: Save output
id: save_output
shell: bash
run: | run: |
mv build/deploy.iso build/${{ env.IMAGE_NAME }}-${{ env.VERSION }}.iso echo "iso_name-${{ matrix.version }}=${{ steps.build.outputs.iso_name}}" >> $GITHUB_OUTPUT
- name: Upload ISO as artifact - name: Upload ISO as artifact
id: upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ${{ env.IMAGE_NAME }}-${{ env.VERSION }}.iso name: ${{ steps.build.outputs.iso_name }}
path: build/*.iso path: |
${{ steps.build.outputs.iso_path }}
${{ steps.build.outputs.iso_path }}-CHECKSUM
if-no-files-found: error if-no-files-found: error
retention-days: 0 retention-days: 0
compression-level: 0 compression-level: 0
overwrite: true overwrite: true
- name: Set status
if: inputs.pr && always()
uses: myrotvorets/set-commit-status-action@v2.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
context: ${{ env.JOB_NAME }}
sha: ${{ env.sha }}
targetUrl: ${{ steps.jobs.outputs.html_url }}
test-iso:
name: Test ISO
env:
JOB_NAME: Test ISO
runs-on: ubuntu-latest
needs:
- build-and-push-iso
permissions:
contents: read
statuses: write
continue-on-error: false
strategy:
fail-fast: false
matrix:
version:
- 38
- 39
- 40
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Switch branch
if: inputs.pr
env:
GITHUB_USER: ${{ github.actor }}
GITHUB_TOKEN: ${{ github.token }}
run: |
sudo apt-get update
sudo apt-get install -y hub
hub pr checkout ${{ inputs.pr }}
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_ENV
- name: Get Current Job Log URL
if: inputs.pr && always()
uses: Tiryoh/gha-jobid-action@v1
id: jobs
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
job_name: "Run Tests / ${{ env.JOB_NAME }}"
- name: Set status
if: inputs.pr && always()
uses: myrotvorets/set-commit-status-action@v2.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
context: ${{ env.JOB_NAME }}
sha: ${{ env.sha }}
targetUrl: ${{ steps.jobs.outputs.html_url }}
- name: Install test tools
run: |
sudo apt-get update
sudo apt-get install -y make
sudo make install-test-deps PACKAGE_MANAGER=apt-get
- name: Download generated ISO
uses: actions/download-artifact@v4
with:
name: ${{ needs['build-and-push-iso']['outputs'][format('iso_name-{0}', matrix.version)] }}
- name: Verify ISO
run: |
checkisomd5 ${{ needs['build-and-push-iso']['outputs'][format('iso_name-{0}', matrix.version)] }}
sha256sum -c ${{ needs['build-and-push-iso']['outputs'][format('iso_name-{0}', matrix.version)] }}-CHECKSUM
- name: Run ISO checks
run: |
mv ${{ needs['build-and-push-iso']['outputs'][format('iso_name-{0}', matrix.version)] }} deploy.iso
make test-iso \
ARCH=${{ env.ARCH}} \
IMAGE_NAME=${{ env.IMAGE_NAME}} \
IMAGE_REPO=${{ env.IMAGE_REPO}} \
IMAGE_TAG=${{ matrix.version }} \
VERSION=${{ matrix.version }} \
VARIANT=${{ env.VARIANT }} \
FLATPAK_REMOTE_REFS_DIR=${{ env.FLATPAK_REMOTE_REFS_DIR }} \
SECURE_BOOT_KEY_URL=${{ env.SECURE_BOOT_KEY_URL }} \
ENROLLMENT_PASSWORD=${{ env.ENROLLMENT_PASSWORD }}
- name: Set status
if: inputs.pr && always()
uses: myrotvorets/set-commit-status-action@v2.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
context: ${{ env.JOB_NAME }}
sha: ${{ env.sha }}
targetUrl: ${{ steps.jobs.outputs.html_url }}
test-deployment:
name: Test deployment
env:
JOB_NAME: Test deployment
runs-on: ubuntu-latest
needs:
- build-and-push-iso
permissions:
contents: read
statuses: write
continue-on-error: false
strategy:
fail-fast: false
matrix:
version:
- 38
- 39
- 40
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Switch branch
if: inputs.pr
env:
GITHUB_USER: ${{ github.actor }}
GITHUB_TOKEN: ${{ github.token }}
run: |
sudo apt-get update
sudo apt-get install -y hub
hub pr checkout ${{ inputs.pr }}
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_ENV
- name: Get Current Job Log URL
if: inputs.pr && always()
uses: Tiryoh/gha-jobid-action@v1
id: jobs
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
job_name: "Run Tests / ${{ env.JOB_NAME }}"
- name: Set status
if: inputs.pr && always()
uses: myrotvorets/set-commit-status-action@v2.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
context: ${{ env.JOB_NAME }}
sha: ${{ env.sha }}
targetUrl: ${{ steps.jobs.outputs.html_url }}
- name: Install test tools
run: |
sudo apt-get update
sudo apt-get install -y make
sudo make install-test-deps PACKAGE_MANAGER=apt-get
- name: Download generated ISO
uses: actions/download-artifact@v4
with:
name: ${{ needs['build-and-push-iso']['outputs'][format('iso_name-{0}', matrix.version)] }}
- name: Add Kickstart and Grub options to ISO
run: |
mv ${{ needs['build-and-push-iso']['outputs'][format('iso_name-{0}', matrix.version)] }} deploy.iso
sudo mkdir /mnt/iso || true
sudo mount -o loop deploy.iso /mnt/iso
cp /mnt/iso/boot/grub2/grub.cfg grub.cfg
sudo umount /mnt/iso
sed -i 's/quiet/console=ttyS0,115200n8 inst.ks=cdrom:\/ks.cfg/' grub.cfg
sed -i 's/set default="1"/set default="0"/' grub.cfg
sed -i 's/set timeout=60/set timeout=1/' grub.cfg
cat << EOF > ks.cfg
lang en_US.UTF-8
keyboard us
timezone Americas/New_York
zerombr
clearpart --all --initlabel
autopart
poweroff
user --name=core --groups=wheel --password=foobar
%include /usr/share/anaconda/interactive-defaults.ks
EOF
xorriso -dialog on << EOF
-indev deploy.iso
-outdev test.iso
-boot_image any replay
-map ks.cfg ks.cfg
-chmod 0444 ks.cfg
-map grub.cfg boot/grub2/grub.cfg
-end
EOF
- name: Create VM disk
run: |
qemu-img create -f qcow2 disk.qcow2 50G
- name: Install the test VM
run: |
timeout 1h qemu-system-x86_64 -name "Anaconda" -boot d -m 4096 -cpu qemu64 -display none -cdrom test.iso -smp 2 -hda disk.qcow2 -serial telnet:localhost:4321,server=on,wait=off & QEMU_PID=$!
echo "PID: $QEMU_PID"
timeout 1m bash -c "while ! (echo > /dev/tcp/127.0.0.1/4321); do sleep 0.1; done"
(nc localhost 4321 | tee vm.stdout) &
wait $QEMU_PID
- name: Start the test VM
env:
VM_USER: core
VM_PASS: foobar
VM_IP: "127.0.0.1"
VM_PORT: "5555"
run: |
mkfifo vm.stdin
qemu-system-x86_64 -name "Anaconda" \
-m 4096 -cpu qemu64 -display none -smp 2 \
-chardev socket,path=/tmp/qga.sock,server=on,wait=off,id=qga0 \
-device e1000,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::${VM_PORT}-:22 \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 \
-boot c -hda disk.qcow2 -serial telnet:localhost:4321,server=on,wait=off & export QEMU_PID=$!
echo "PID: $QEMU_PID"
timeout 1m bash -c "while ! (echo > /dev/tcp/127.0.0.1/4321); do sleep 0.1; done"
(tail -f vm.stdin | nc localhost 4321 | tee vm.stdout) &
timeout 30m bash -c "while ! (echo > /dev/tcp/${VM_IP}/${VM_PORT}); do sleep 1; done"
if ! (echo > /dev/tcp/${VM_IP}/${VM_PORT})
then
echo "SSH must be installed and enabled inside the container"
fi
echo "VM ready for tests at IP ${VM_IP}:${VM_PORT}"
make test-vm VM_IP=${VM_IP} VM_PORT=${VM_PORT} VM_USER=${VM_USER} VM_PASS=${VM_PASS} \
ARCH=${{ env.ARCH}} \
IMAGE_NAME=${{ env.IMAGE_NAME}} \
IMAGE_REPO=${{ env.IMAGE_REPO}} \
IMAGE_TAG=${{ matrix.version }} \
VERSION=${{ matrix.version }} \
VARIANT=${{ env.VARIANT }} \
FLATPAK_REMOTE_REFS_DIR=${{ env.FLATPAK_REMOTE_REFS_DIR }} \
SECURE_BOOT_KEY_URL=${{ env.SECURE_BOOT_KEY_URL }} \
ENROLLMENT_PASSWORD=${{ env.ENROLLMENT_PASSWORD }}
kill $QEMU_PID
- name: Set status
if: inputs.pr && always()
uses: myrotvorets/set-commit-status-action@v2.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
context: ${{ env.JOB_NAME }}
sha: ${{ env.sha }}
targetUrl: ${{ steps.jobs.outputs.html_url }}

32
.github/workflows/stale.yml vendored Normal file
View file

@ -0,0 +1,32 @@
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/actions/stale
name: Mark stale issues and pull requests
on:
schedule:
- cron: '39 21 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'Issue is stale and will be closed in 14 days if there is no further activity'
stale-pr-message: 'Pull request is stale and will be closed in 14 days if there is no further activity'
stale-issue-label: 'no-issue-activity'
stale-pr-label: 'no-pr-activity'
days-before-stale: 60
days-before-close: 17
remove-stale-when-updated: true
only-issue-labels: help wanted

27
.github/workflows/variables.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: Repo Tests
on:
push:
branches:
- 'main'
tags:
- 'v*'
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
variables:
name: Check variables are listed
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Run test
run: |
/bin/bash tests/repo/vars.sh

2
.gitignore vendored
View file

@ -1,9 +1,9 @@
/debugdata /debugdata
/build /build
/lorax_templates/post_*
/pkglists /pkglists
/repos /repos
/results /results
/lorax_templates/*.tmpl
/xorriso/input.txt /xorriso/input.txt
/xorriso/*.sh /xorriso/*.sh
/original-pkgsizes.txt /original-pkgsizes.txt

7
.gitmodules vendored Normal file
View file

@ -0,0 +1,7 @@
[submodule "external/fedora-lorax-templates"]
path = external/fedora-lorax-templates
url = https://pagure.io/fedora-lorax-templates.git
branch = f39
[submodule "external/lorax"]
path = external/lorax
url = https://github.com/weldr/lorax.git

View file

@ -1,6 +1,6 @@
FROM fedora:39 FROM fedora:40
ARG VERSION=39 ARG VERSION=40
ENV ARCH="x86_64" ENV ARCH="x86_64"
ENV IMAGE_NAME="base" ENV IMAGE_NAME="base"
@ -11,16 +11,15 @@ ENV VERSION="${VERSION}"
ENV WEB_UI="false" ENV WEB_UI="false"
RUN mkdir /build-container-installer RUN mkdir /build-container-installer
COPY /lorax_templates /build-container-installer/lorax_templates
COPY /xorriso /build-container-installer/xorriso COPY / /build-container-installer/
COPY /Makefile /build-container-installer
COPY /entrypoint.sh /
WORKDIR /build-container-installer WORKDIR /build-container-installer
VOLUME /build-container-installer/build
VOLUME /build-container-installer/repos
VOLUME /cache
RUN dnf install -y make && make install-deps RUN dnf install -y make && make install-deps
VOLUME /build-container-installer/build ENTRYPOINT ["/bin/bash", "/build-container-installer/entrypoint.sh"]
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]

259
Makefile
View file

@ -1,92 +1,163 @@
# Configuration vars # Configuration vars
## Formatting = UPPERCASE ## Formatting = UPPERCASE
# General
ADDITIONAL_TEMPLATES =
ARCH = x86_64 ARCH = x86_64
VERSION = 39 EXTRA_BOOT_PARAMS =
IMAGE_REPO = quay.io/fedora-ostree-desktops
IMAGE_NAME = base IMAGE_NAME = base
IMAGE_REPO = quay.io/fedora-ostree-desktops
IMAGE_TAG = $(VERSION) IMAGE_TAG = $(VERSION)
REPOS = $(subst :,\:,$(shell ls /etc/yum.repos.d/*.repo))
ROOTFS_SIZE = 4
VARIANT = Server VARIANT = Server
VERSION = 39
WEB_UI = false WEB_UI = false
REPOS = /etc/yum.repos.d/fedora.repo /etc/yum.repos.d/fedora-updates.repo # Flatpak
FLATPAK_REMOTE_NAME = flathub
FLATPAK_REMOTE_URL = https://flathub.org/repo/flathub.flatpakrepo
FLATPAK_REMOTE_REFS =
FLATPAK_REMOTE_REFS_DIR =
# Secure boot
ENROLLMENT_PASSWORD = ENROLLMENT_PASSWORD =
SECURE_BOOT_KEY_URL = SECURE_BOOT_KEY_URL =
ADDITIONAL_TEMPLATES = ""
ROOTFS_SIZE = 4
# Generated vars ###################
# Hidden vars
# Cache
DNF_CACHE =
PACKAGE_MANAGER = dnf
# Functions
## Formatting = lowercase
# Get a list of templates for the feature
# $1 = feature
get_templates = $(shell ls lorax_templates/$(1)_*.tmpl) \
$(foreach file,$(notdir $(shell ls lorax_templates/scripts/post/$(1)_*)),lorax_templates/post_$(file).tmpl)
# Get a list of tests for the feature
# $1 = test type
# $2 = feature
run_tests = tests="$(shell ls tests/$(1)/$(2)_*)"; \
if [ -n "$$tests" ]; \
then \
chmod +x $$tests; \
for test in $$tests; \
do \
$(foreach var,$(_VARS),$(var)=$($(var))) ./$${test}; \
RC=$$?; if [ $$RC != 0 ]; then exit $$RC; fi; \
done; \
fi
# Converts a post script to a template
# $1 = script to convert
# $2 = file on ISO to write
# $3 = whether to copy the '<%' lines to the template
convert_post_to_tmpl = header=0; \
skip=0; \
while read -r line; \
do \
if [[ $$line =~ ^\<\% ]]; \
then \
if [[ '$(3)' == 'true' ]]; \
then \
echo $$line >> lorax_templates/post_$(1).tmpl; \
fi; \
echo >> lorax_templates/post_$(1).tmpl; \
else \
if [[ $$header == 0 ]]; \
then \
if [[ $$line =~ ^\#\#\ (.*)$$ ]]; \
then \
echo "append $(2) \"%post --erroronfail $${BASH_REMATCH[1]}\"" >> lorax_templates/post_$(1).tmpl; \
skip=1; \
else \
echo "append $(2) \"%post --erroronfail\"" >> lorax_templates/post_$(1).tmpl; \
fi; \
header=1; \
fi; \
if [[ $$skip == 0 ]]; \
then \
echo "append $(2) \"$${line//\"/\\\"}\"" >> lorax_templates/post_$(1).tmpl; \
fi; \
skip=0; \
fi; \
done < lorax_templates/scripts/post/$(1); \
echo "append $(2) \"%end\"" >> lorax_templates/post_$(1).tmpl
# Generated/internal vars
## Formatting = _UPPERCASE ## Formatting = _UPPERCASE
_BASE_DIR = $(shell pwd) _BASE_DIR = $(shell pwd)
_IMAGE_REPO_ESCAPED = $(subst /,\/,$(IMAGE_REPO)) _IMAGE_REPO_ESCAPED = $(subst /,\/,$(IMAGE_REPO))
_IMAGE_REPO_DOUBLE_ESCAPED = $(subst \,\\\,$(_IMAGE_REPO_ESCAPED)) _IMAGE_REPO_DOUBLE_ESCAPED = $(subst \,\\\,$(_IMAGE_REPO_ESCAPED))
_VOLID = $(firstword $(subst -, ,$(IMAGE_NAME)))-$(ARCH)-$(IMAGE_TAG) _LORAX_ARGS =
_LORAX_TEMPLATES = $(call get_templates,install)
_REPO_FILES = $(subst /etc/yum.repos.d,repos,$(REPOS)) _REPO_FILES = $(subst /etc/yum.repos.d,repos,$(REPOS))
_LORAX_TEMPLATES = $(subst .in,,$(shell ls lorax_templates/*.tmpl.in)) $(foreach file,$(shell ls lorax_templates/scripts/post),lorax_templates/post_$(file).tmpl) _TEMP_DIR = $(shell mktemp -d)
_TEMPLATE_VARS = ARCH VERSION IMAGE_REPO IMAGE_NAME IMAGE_TAG VARIANT WEB_UI REPOS _IMAGE_REPO_ESCAPED _IMAGE_REPO_DOUBLE_ESCAPED _TEMPLATE_VARS = ARCH _BASE_DIR IMAGE_NAME IMAGE_REPO _IMAGE_REPO_DOUBLE_ESCAPED _IMAGE_REPO_ESCAPED IMAGE_TAG REPOS _RHEL VARIANT VERSION WEB_UI
_VOLID = $(firstword $(subst -, ,$(IMAGE_NAME)))-$(ARCH)-$(IMAGE_TAG)
ifeq ($(VARIANT),Server) ifeq ($(findstring redhat.repo,$(REPOS)),redhat.repo)
_LORAX_ARGS = --macboot --noupgrade _RHEL = true
else else
_LORAX_ARGS = --nomacboot _RHEL = false
endif
ifeq ($(_RHEL),true)
_LORAX_ARGS += --nomacboot --noupgrade
else ifeq ($(VARIANT),Server)
_LORAX_ARGS += --macboot --noupgrade
else
_LORAX_ARGS += --nomacboot
endif endif
ifeq ($(WEB_UI),true) ifeq ($(WEB_UI),true)
_LORAX_ARGS += -i anaconda-webui _LORAX_ARGS += -i anaconda-webui
endif endif
# Step 7: Buid end ISO ifneq ($(DNF_CACHE),)
_LORAX_ARGS += --cachedir $(DNF_CACHE)
_LORAX_TEMPLATES += $(call get_templates,cache)
_TEMPLATE_VARS += DNF_CACHE
endif
ifneq ($(FLATPAK_REMOTE_REFS_DIR),)
COLLECTED_REFS = $(foreach file,$(shell ls $(FLATPAK_REMOTE_REFS_DIR)/*),$(shell cat $(file)))
FLATPAK_REMOTE_REFS += $(sort $(COLLECTED_REFS))
endif
ifneq ($(FLATPAK_REMOTE_REFS),)
_FLATPAK_REPO_GPG = $(shell curl -L $(FLATPAK_REMOTE_URL) | grep -i '^GPGKey=' | cut -d= -f2)
_FLATPAK_REPO_URL = $(shell curl -L $(FLATPAK_REMOTE_URL) | grep -i '^URL=' | cut -d= -f2)
_LORAX_ARGS += -i flatpak-libs
_LORAX_TEMPLATES += $(call get_templates,flatpak) \
external/fedora-lorax-templates/ostree-based-installer/lorax-embed-flatpaks.tmpl
_TEMPLATE_VARS += FLATPAK_REMOTE_NAME FLATPAK_REMOTE_REFS FLATPAK_REMOTE_URL _FLATPAK_REPO_GPG _FLATPAK_REPO_URL
endif
ifneq ($(SECURE_BOOT_KEY_URL),)
_LORAX_TEMPLATES += $(call get_templates,secureboot)
_TEMPLATE_VARS += ENROLLMENT_PASSWORD
endif
# Step 7: Build end ISO
## Default action ## Default action
build/deploy.iso: boot.iso container/$(IMAGE_NAME)-$(IMAGE_TAG) xorriso/input.txt build/deploy.iso: boot.iso container/$(IMAGE_NAME)-$(IMAGE_TAG) xorriso/input.txt
mkdir $(_BASE_DIR)/build || true mkdir $(_BASE_DIR)/build || true
xorriso -dialog on < $(_BASE_DIR)/xorriso/input.txt xorriso -dialog on < $(_BASE_DIR)/xorriso/input.txt
implantisomd5 build/deploy.iso implantisomd5 build/deploy.iso
external/lorax/branch-$(VERSION):
git config advice.detachedHead false
cd external/lorax && git reset --hard HEAD && git checkout tags/$(shell cd external/lorax && git tag -l lorax-$(VERSION).* --sort=creatordate | tail -n 1)
touch external/lorax/branch-$(VERSION)
# Step 1: Generate Lorax Templates # Step 1: Generate Lorax Templates
lorax_templates/post_%.tmpl: lorax_templates/scripts/post/% lorax_templates/post_%.tmpl: lorax_templates/scripts/post/%
# Support interactive-defaults.ks $(call convert_post_to_tmpl,$*,usr/share/anaconda/post-scripts/$*.ks,true)
$(eval _ISO_FILE = usr/share/anaconda/interactive-defaults.ks)
header=0; \
while read -r line; \
do \
if [[ $$line =~ ^\<\% ]]; \
then \
echo $$line >> lorax_templates/post_$*.tmpl; \
echo >> lorax_templates/post_$*.tmpl; \
else \
if [[ $$header == 0 ]]; \
then \
echo "append $(_ISO_FILE) \"%post --erroronfail\"" >> lorax_templates/post_$*.tmpl; \
header=1; \
fi; \
echo "append $(_ISO_FILE) \"$$line\"" >> lorax_templates/post_$*.tmpl; \
fi; \
done < lorax_templates/scripts/post/$*
echo "append $(_ISO_FILE) \"%end\"" >> lorax_templates/post_$*.tmpl
# Support new Anaconda method
$(eval _ISO_FILE = usr/share/anaconda/post-scripts/configure_upgrades.ks)
header=0; \
while read -r line; \
do \
if [[ $$line =~ ^\<\% ]]; \
then \
echo >> lorax_templates/post_$*.tmpl; \
else \
if [[ $$header == 0 ]]; \
then \
echo "append $(_ISO_FILE) \"%post --erroronfail\"" >> lorax_templates/post_$*.tmpl; \
header=1; \
fi; \
echo "append $(_ISO_FILE) \"$$line\"" >> lorax_templates/post_$*.tmpl; \
fi; \
done < lorax_templates/scripts/post/$*
echo "append $(_ISO_FILE) \"%end\"" >> lorax_templates/post_$*.tmpl
lorax_templates/%.tmpl: lorax_templates/%.tmpl.in
$(eval _VARS = IMAGE_NAME IMAGE_TAG _IMAGE_REPO_DOUBLE_ESCAPED _IMAGE_REPO_ESCAPED)
$(foreach var,$(_VARS),$(var)=$($(var))) envsubst '$(foreach var,$(_VARS),$$$(var))' < $(_BASE_DIR)/lorax_templates/$*.tmpl.in > $(_BASE_DIR)/lorax_templates/$*.tmpl
repos: $(_REPO_FILES)
# Step 2: Replace vars in repo files # Step 2: Replace vars in repo files
repos/%.repo: /etc/yum.repos.d/%.repo repos/%.repo: /etc/yum.repos.d/%.repo
@ -95,32 +166,30 @@ repos/%.repo: /etc/yum.repos.d/%.repo
sed -i "s/\$$releasever/${VERSION}/g" $(_BASE_DIR)/repos/$*.repo sed -i "s/\$$releasever/${VERSION}/g" $(_BASE_DIR)/repos/$*.repo
sed -i "s/\$$basearch/${ARCH}/g" $(_BASE_DIR)/repos/$*.repo sed -i "s/\$$basearch/${ARCH}/g" $(_BASE_DIR)/repos/$*.repo
# Don't do anything for custom repos
%.repo:
# Step 3: Build boot.iso using Lorax # Step 3: Build boot.iso using Lorax
boot.iso: $(_LORAX_TEMPLATES) $(_REPO_FILES) boot.iso: external/lorax/branch-$(VERSION) $(filter lorax_templates/%,$(_LORAX_TEMPLATES)) $(_REPO_FILES)
rm -Rf $(_BASE_DIR)/results || true rm -Rf $(_BASE_DIR)/results || true
rm /etc/rpm/macros.image-language-conf || true mv /etc/rpm/macros.image-language-conf $(_TEMP_DIR)/macros.image-language-conf || true
# Set the enrollment password
sed 's/@ENROLLMENT_PASSWORD@/$(ENROLLMENT_PASSWORD)/' $(_BASE_DIR)/scripts/enroll-secureboot-key.sh.in > $(_BASE_DIR)/scripts/enroll-secureboot-key.sh
# Download the secure boot key # Download the secure boot key
if [ -n "$(SECURE_BOOT_KEY_URL)" ]; then\ if [ -n "$(SECURE_BOOT_KEY_URL)" ]; \
then \
curl --fail -L -o $(_BASE_DIR)/sb_pubkey.der $(SECURE_BOOT_KEY_URL); \ curl --fail -L -o $(_BASE_DIR)/sb_pubkey.der $(SECURE_BOOT_KEY_URL); \
fi fi
lorax -p $(IMAGE_NAME) -v $(VERSION) -r $(VERSION) -t $(VARIANT) \ lorax -p $(IMAGE_NAME) -v $(VERSION) -r $(VERSION) -t $(VARIANT) \
--isfinal --squashfs-only --buildarch=$(ARCH) --volid=$(_VOLID) \ --isfinal --squashfs-only --buildarch=$(ARCH) --volid=$(_VOLID) --sharedir $(_BASE_DIR)/external/lorax/share/templates.d/99-generic \
$(_LORAX_ARGS) \ $(_LORAX_ARGS) \
$(foreach file,$(_REPO_FILES),--repo $(_BASE_DIR)/$(file)) \ $(foreach file,$(_REPO_FILES),--repo $(_BASE_DIR)/$(file)) \
$(foreach file,$(_LORAX_TEMPLATES),--add-template $(_BASE_DIR)/$(file)) \ $(foreach file,$(_LORAX_TEMPLATES),--add-template $(_BASE_DIR)/$(file)) \
$(foreach file,$(ADDITIONAL_TEMPLATES),--add-template $(file)) \ $(foreach file,$(ADDITIONAL_TEMPLATES),--add-template $(file)) \
$(foreach file,$(_FLATPAK_TEMPLATES),--add-template $(file)) \
$(foreach file,$(_EXTERNAL_TEMPLATES),--add-template $(_BASE_DIR)/external/$(file)) \
--rootfs-size $(ROOTFS_SIZE) \ --rootfs-size $(ROOTFS_SIZE) \
$(foreach var,$(_TEMPLATE_VARS),--add-template-var "$(shell echo $(var) | tr '[:upper:]' '[:lower:]')=$($(var))") \ $(foreach var,$(_TEMPLATE_VARS),--add-template-var "$(shell echo $(var) | tr '[:upper:]' '[:lower:]')=$($(var))") \
$(_BASE_DIR)/results/ $(_BASE_DIR)/results/
mv $(_BASE_DIR)/results/images/boot.iso $(_BASE_DIR)/ mv $(_BASE_DIR)/results/images/boot.iso $(_BASE_DIR)/
mv -f $(_TEMP_DIR)/macros.image-language-conf /etc/rpm/macros.image-language-conf || true
# Step 4: Download container image # Step 4: Download container image
container/$(IMAGE_NAME)-$(IMAGE_TAG): container/$(IMAGE_NAME)-$(IMAGE_TAG):
@ -129,6 +198,8 @@ container/$(IMAGE_NAME)-$(IMAGE_TAG):
# Step 5: Generate xorriso script # Step 5: Generate xorriso script
xorriso/%.sh: xorriso/%.sh.in xorriso/%.sh: xorriso/%.sh.in
sed -i 's/quiet/quiet $(EXTRA_BOOT_PARAMS)/g' results/boot/grub2/grub.cfg
sed -i 's/quiet/quiet $(EXTRA_BOOT_PARAMS)/g' results/EFI/BOOT/grub.cfg
$(eval _VARS = IMAGE_NAME IMAGE_TAG ARCH VERSION) $(eval _VARS = IMAGE_NAME IMAGE_TAG ARCH VERSION)
$(foreach var,$(_VARS),$(var)=$($(var))) envsubst '$(foreach var,$(_VARS),$$$(var))' < $(_BASE_DIR)/xorriso/$*.sh.in > $(_BASE_DIR)/xorriso/$*.sh $(foreach var,$(_VARS),$(var)=$($(var))) envsubst '$(foreach var,$(_VARS),$$$(var))' < $(_BASE_DIR)/xorriso/$*.sh.in > $(_BASE_DIR)/xorriso/$*.sh
@ -153,7 +224,57 @@ clean:
rm -f $(_BASE_DIR)/*.log || true rm -f $(_BASE_DIR)/*.log || true
install-deps: install-deps:
dnf install -y lorax xorriso skopeo if [ "$(PACKAGE_MANAGER)" =~ apt.* ]; then $(PACKAGE_MANAGER) update; fi
$(PACKAGE_MANAGER) install -y lorax xorriso skopeo flatpak dbus-daemon ostree coreutils gettext git
.PHONY: clean install-deps install-test-deps:
if [ "$(PACKAGE_MANAGER)" =~ apt.* ]; then $(PACKAGE_MANAGER) update; fi
$(PACKAGE_MANAGER) install -y qemu qemu-utils xorriso unzip qemu-system-x86 netcat socat jq isomd5sum ansible make coreutils squashfs-tools
test: test-iso test-vm
test-repo:
bash tests/repo/vars.sh
test-iso:
$(eval _VARS = VERSION FLATPAK_REMOTE_NAME _FLATPAK_REPO_URL)
sudo modprobe loop
sudo mkdir /mnt/iso /mnt/install
sudo mount -o loop deploy.iso /mnt/iso
sudo mount -t squashfs -o loop /mnt/iso/images/install.img /mnt/install
# install tests
$(call run_tests,iso,install)
# flapak tests
if [ -n "$(FLATPAK_REMOTE_REFS)" ]; then $(call run_tests,iso,flatpak); fi
# Cleanup
sudo umount /mnt/install
sudo umount /mnt/iso
ansible_inventory:
echo "ungrouped:" > ansible_inventory
echo " hosts:" >> ansible_inventory
echo " vm:" >> ansible_inventory
echo " ansible_host: ${VM_IP}" >> ansible_inventory
echo " ansible_port: ${VM_PORT}" >> ansible_inventory
echo " ansible_user: ${VM_USER}" >> ansible_inventory
echo " ansible_password: ${VM_PASS}" >> ansible_inventory
echo " ansible_become_pass: ${VM_PASS}" >> ansible_inventory
echo " ansible_ssh_common_args: '-o StrictHostKeyChecking=no'" >> ansible_inventory
test-vm: ansible_inventory
$(eval _VARS = IMAGE_REPO IMAGE_NAME IMAGE_TAG)
ansible -i ansible_inventory -m ansible.builtin.wait_for_connection vm
# install tests
$(call run_tests,vm,install)
# flapak tests
if [ -n "$(FLATPAK_REMOTE_REFS)" ]; then $(call run_tests,vm,flatpak); fi
.PHONY: clean install-deps install-test-deps test test-iso test-vm

View file

@ -1,4 +1,4 @@
![Build status](https://github.com/jasonn3/build-container-installer/actions/workflows/build-and-test.yml/badge.svg??event=push) ![Build status](https://github.com/jasonn3/build-container-installer/actions/workflows/build-and-test.yml/badge.svg?event=push)
# Build Container Installer Action # Build Container Installer Action
This action is used to enerate an ISO for installing an OSTree stored in a container image. This utilizes the anaconda command `ostreecontainer` This action is used to enerate an ISO for installing an OSTree stored in a container image. This utilizes the anaconda command `ostreecontainer`
@ -7,13 +7,29 @@ This action is used to enerate an ISO for installing an OSTree stored in a conta
This action is designed to be called from a GitHub workflow using the following format This action is designed to be called from a GitHub workflow using the following format
```yaml ```yaml
- name: Build ISO - name: Build ISO
uses: jasonn3/build-container-installer/v1.0.0 uses: jasonn3/build-container-installer@main
id: build
with: with:
arch: ${{ env.ARCH}} arch: ${{ env.ARCH}}
image_name: ${{ env.IMAGE_NAME}} image_name: ${{ env.IMAGE_NAME}}
image_repo: ${{ env.IMAGE_REPO}} image_repo: ${{ env.IMAGE_REPO}}
image_tag: ${{ env.IMAGE_TAG }}
version: ${{ env.VERSION }} version: ${{ env.VERSION }}
variant: ${{ env.VARIANT }} variant: ${{ env.VARIANT }}
iso_name: ${{ env.IMAGE_NAME }}-${{ env.IMAGE_TAG }}-${{ env.VERSION }}.iso
# This example is for uploading your ISO as a Github artifact. You can do something similar using any cloud storage, so long as you copy the output
- name: Upload ISO as artifact
id: upload
uses: actions/upload-artifact@v4
with:
name: ${{ steps.build.outputs.iso_name }}
path: |
${{ steps.build.outputs.iso_path }}
${{ steps.build.outputs.iso_path }}-CHECKSUM
if-no-files-found: error
retention-days: 0
compression-level: 0
``` ```
See [Customizing](#customizing) for information about customizing the ISO that gets created using `with` See [Customizing](#customizing) for information about customizing the ISO that gets created using `with`
@ -21,46 +37,67 @@ See [Customizing](#customizing) for information about customizing the ISO that g
## Customizing ## Customizing
The following variables can be used to customize the created ISO. The following variables can be used to customize the created ISO.
| Variable | Description | Default Value | ### Inputs
| ----------------- | -------------------------------------------------------- | ------------------------------ | | Variable | Description | Default Value | Action | Container | Makefile |
| ARCH | Architecture for image to build | x86_64 | | ----------------------- | ---------------------------------------------------------------------------- | -------------------------------------------- | ------------------ | ------------------ | ------------------ |
| VERSION | Fedora version of installer to build | 39 | | additional_templates | Space delimited list of additional Lorax templates to include | \[empty\] | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| IMAGE_REPO | Repository containing the source container image | quay.io/fedora-ostree-desktops | | arch | Architecture for image to build | x86_64 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| IMAGE_NAME | Name of the source container image | base | | enrollment_password | Used for supporting secure boot (requires SECURE_BOOT_KEY_URL to be defined) | container-installer | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| IMAGE_TAG | Tag of the source container image | *VERSION* | | extra_boot_params | Extra params used by grub to boot the anaconda installer | \[empty\] | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| EXTRA_BOOT_PARAMS | Extra params used by grub to boot the anaconda installer | \[empty\] | | flatpak_remote_name | Name of the Flatpak repo on the destination OS | flathub | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| VARIANT | Source container variant\* | Server | | flatpak_remote_refs | Space separated list of flatpak refs to install | \[empty\] | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WEB_UI | Enable Anaconda WebUI (experimental) | false | | flatpak_remote_refs_dir | Directory that contains files that list the flatpak refs to install | \[empty\] | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| flatpak_remote_url | URL of the flatpakrepo file | https://flathub.org/repo/flathub.flatpakrepo | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| image_name | Name of the source container image | base | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| image_repo | Repository containing the source container image | quay.io/fedora-ostree-desktops | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| image_tag | Tag of the source container image | *VERSION* | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| iso_name | Name of the ISO you wish to output when completed | build/deploy.iso | :white_check_mark: | :x: | :x: |
| repos | List of repo files for Lorax to use | /etc/yum.repos.d/*.repo | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| rootfs_size | The size (in GiB) for the squashfs runtime volume | 2 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| secure_boot_key_url | Secure boot key that is installed from URL location\*\* | \[empty\] | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| variant | Source container variant\* | Server | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| version | Fedora version of installer to build | 39 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| web_ui | Enable Anaconda WebUI (experimental) | false | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Available options for VARIANT can be found by running `dnf provides system-release`. \*Available options for VARIANT can be found by running `dnf provides system-release`.
Variant will be the third item in the package name. Example: `fedora-release-kinoite-39-34.noarch` will be kinoite Variant will be the third item in the package name. Example: `fedora-release-kinoite-39-34.noarch` will be kinoite
\*\* If you need to reference a local file, you can use `file://*path*`
### Outputs
| Variable | Description | Usage |
| -------- | ----------------------------------------| ------------------------------------------------ |
| iso_name | The name of the resulting .iso | ${{ steps.YOUR_ID_FOR_ACTION.outputs.iso_name }} |
| iso_path | The name and path of the resulting .iso | ${{ steps.YOUR_ID_FOR_ACTION.outputs.iso_name }} |
For outputs, see example above.
## Development ## Development
### Makefile ### Makefile
The Makefile contains all of the commands that are run in the action. There are separate targets for each file generated, however `make` can be used to generate the final image and `make clean` can be used to clean up the workspace. The resulting ISO will be stored in the `build` directory. The Makefile contains all of the commands that are run in the action. There are separate targets for each file generated, however `make` can be used to generate the final image and `make clean` can be used to clean up the workspace. The resulting ISO will be stored in the `build` directory.
`make install-deps` can be used to install the necessary packages `make install-deps` can be used to install the necessary packages
See [Customizing](#customizing) for information about customizing the ISO that gets created. See [Customizing](#customizing) for information about customizing the ISO that gets created. All variable should be specified CAPITALIZED.
### Container ### Container
A container with `make install-deps` already run is provided at `ghcr.io/jasonn3/build-container-installer:latest` A container with `make install-deps` already run is provided at `ghcr.io/jasonn3/build-container-installer:latest`
To use the container file, run `docker run --privileged --volume .:/build-container-installer/build ghcr.io/jasonn3/build-container-installer:latest`. To use the container file, run `docker run --privileged --volume .:/build-container-installer/build ghcr.io/jasonn3/build-container-installer:latest`.
This will create an ISO with the baked in defaults of the container image. This will create an ISO with the baked in defaults of the container image. The resulting file will be called `deploy.iso`
See [Customizing](#customizing) for information about customizing the ISO that gets created. The variable can either be defined as environment variables. See [Customizing](#customizing) for information about customizing the ISO that gets created. The variable can either be defined as environment variables. All variable should be specified CAPITALIZED.
Examples: Examples:
Building an ISO to install Fedora 38 Building an ISO to install Fedora 38
```bash ```bash
docker run --rm --privileged --volume .:/build-container-installer/build -e VERSION=38 -e IMAGE_NAME=base -e IMAGE_TAG=38 -e VARIANT=Server ghcr.io/jasonn3/build-container-installer:latest docker run --rm --privileged --volume .:/github/workspace/build ghcr.io/jasonn3/build-container-installer:latest VERSION=38 IMAGE_NAME=base IMAGE_TAG=38 VARIANT=Server
``` ```
Building an ISO to install Fedora 39 Building an ISO to install Fedora 39
```bash ```bash
docker run --rm --privileged --volume .:/build-container-installer/build -e VERSION=39 -e IMAGE_NAME=base -e IMAGE_TAG=39 -e VARIANT=Server ghcr.io/jasonn3/build-container-installer:latest docker run --rm --privileged --volume .:/github/workspace/build ghcr.io/jasonn3/build-container-installer:latest VERSION=39 IMAGE_NAME=base IMAGE_TAG=39 VARIANT=Server
``` ```
### VSCode Dev Container ### VSCode Dev Container
@ -105,4 +142,3 @@ Build a new container image:
"privileged": true "privileged": true
} }
``` ```

View file

@ -2,10 +2,51 @@ name: Build Container Installer
description: Generates an ISO for installing an OSTree stored in a container image description: Generates an ISO for installing an OSTree stored in a container image
inputs: inputs:
action_version:
description: Version of the action container to run
deprecationMessage: No longer used. github.action_ref replaces the need for this. Will be removed in a future version.
required: false
additional_templates:
description: Space delimited list of additional Lorax templates to include
required: false
arch: arch:
description: Architecture for image to build description: Architecture for image to build
required: true required: true
default: x86_64 default: x86_64
dnf_cache_key:
description: Overrides the dnf cache key
required: false
enable_cache_dnf:
description: Whether to enable caching for dnf
required: false
default: "true"
enable_cache_skopeo:
description: Whether to enable caching for skopeo
required: false
default: "false"
enrollment_password:
description: Used for supporting secure boot (requires secure_boot_key_url to be defined)
required: false
default: "container-installer"
extra_boot_params:
description: Extra params used by grub to boot the anaconda installer
required: false
flatpak_remote_name:
description: Name of the Flatpak remote repo
required: false
default: "flathub"
flatpak_remote_refs:
description: Space delimited list of refs to the flatpak packages to install
required: false
default: ""
flatpak_remote_refs_dir:
description: Directory that contains files that list the flatpak refs to install
required: false
default: ""
flatpak_remote_url:
description: The URL of the Flatpak remote flatpakrepo file
required: false
default: https://flathub.org/repo/flathub.flatpakrepo
image_name: image_name:
description: Name of the source container image description: Name of the source container image
required: true required: true
@ -14,6 +55,24 @@ inputs:
description: Repository containing the source container image description: Repository containing the source container image
required: true required: true
default: quay.io/fedora-ostree-desktops default: quay.io/fedora-ostree-desktops
image_tag:
description: Tag of the source container image. Defaults to the installer version
required: false
iso_name:
description: "Name of the resulting ISO. Relative paths are relative to github.workspace"
required: false
default: build/deploy.iso
repos:
description: List of repo files for Lorax to use
required: false
rootfs_size:
description: The size (in GiB) for the squashfs runtime volume
secure_boot_key_url:
description: Secure boot key that is installed from URL location
required: false
skopeo_cache_key:
description: Overrides the skopeo cache key
required: false
variant: variant:
description: "Source container variant. Available options can be found by running `dnf provides system-release`. Variant will be the third item in the package name. Example: `fedora-release-kinoite-39-34.noarch` will be kinonite" description: "Source container variant. Available options can be found by running `dnf provides system-release`. Variant will be the third item in the package name. Example: `fedora-release-kinoite-39-34.noarch` will be kinonite"
required: true required: true
@ -22,53 +81,153 @@ inputs:
description: Fedora version of installer to build description: Fedora version of installer to build
required: true required: true
default: "39" default: "39"
image_tag:
description: Tag of the source container image. Defaults to the installer version
required: false
web_ui: web_ui:
description: Enable Anaconda WebUI description: Enable Anaconda WebUI
required: false required: false
default: "false" default: "false"
enrollment_password:
description: Used for supporting secure boot (requires SECURE_BOOT_KEY_URL to be defined) outputs:
required: false iso_name:
default: "container-installer" value: ${{ steps.rename_iso.outputs.iso_name }}
secure_boot_key_url: description: The name of the resulting .iso
description: Secure boot key that is installed from URL location iso_path:
required: false value: ${{ steps.rename_iso.outputs.iso_path }}
action_version: description: The name and path of the resulting .iso
description: Version of the action container to run
deprecationMessage: No longer used. github.action_ref replaces the need for this. Will be removed in a future version.
required: false
additional_templates:
description: Space delimetered list of additional Lorax templates to include
required: false
runs: runs:
using: composite using: composite
steps: steps:
- name: Lowercase Registry - name: Make cache directory
id: registry_case
uses: ASzc/change-string-case-action@v6
with:
string: ghcr.io/${{ github.repository }}
- name: Run docker image
shell: bash shell: bash
run: | run: |
# Check if running inside of the action repo sudo mkdir /cache
if [[ -z "${{ github.action_ref }}" ]]; then if [[ "${{ github.ref_name }}" =~ (.*)/merge ]]; then tag=pr-${BASH_REMATCH[1]}; else tag=${{ github.ref_name }}; fi; fi sudo chmod 777 /cache
if [[ -z "${tag}" ]]; then tag=${{ github.action_ref }}; fi
image=${{ steps.registry_case.outputs.lowercase }}
docker run --privileged --volume .:/github/workspace/ ${image}:${tag} \
ARCH=${{ inputs.arch }} \
IMAGE_NAME=${{ inputs.image_name }} \
IMAGE_REPO=${{ inputs.image_repo }} \
VARIANT=${{ inputs.variant }} \
VERSION=${{ inputs.version }} \
IMAGE_TAG=${{ inputs.image_tag || inputs.version }} \
WEB_UI=${{ inputs.web_ui }} \
ENROLLMENT_PASSWORD=${{ inputs.enrollment_password }} \
SECURE_BOOT_KEY_URL=${{ inputs.secure_boot_key_url }} \
"ADDITIONAL_TEMPLATES=${{ inputs.additional_templates }}"
- name: Load dnf cache
id: load_dnf_cache
env:
dnf_cache_key: dnf-${{ inputs.version }}
if: inputs.enable_cache_dnf == 'true'
uses: actions/cache/restore@v4
with:
path: /cache/dnf
key: ${{ inputs.dnf_cache_key || env.dnf_cache_key }}
- name: Load skopeo cache
id: load_skopeo_cache
env:
skopeo_cache_key: skopeo-${{ inputs.image_name }}-${{ inputs.version || inputs.image_tag }}
if: inputs.enable_cache_skopeo == 'true'
uses: actions/cache/restore@v4
with:
path: /cache/skopeo
key: ${{ inputs.skopeo_cache_key || env.skopeo_cache_key }}
- name: Ensure cache directories exist
shell: bash
run: |
mkdir /cache/dnf || true
mkdir /cache/dnf_new || true
mkdir /cache/skopeo || true
- name: Run docker image
env:
ACTION_REPO: ${{ github.action_repository }}
ACTION_REF: ${{ github.action_ref }}
shell: bash
run: |
image="ghcr.io/jasonn3/build-container-installer"
# Check if running inside of the action repo
if [[ -z "${ACTION_REPO}" || "${ACTION_REPO}" == "${{ github.repository }}" ]]
then
if [[ "${{ github.ref_name }}" =~ (.*)/merge ]]
then
tag="pr-${BASH_REMATCH[1]}"
image="docker.io/jasonn3/build-container-installer"
else
tag="${{ github.ref_name }}"
fi
else
tag="${ACTION_REF}"
fi
if [[ "${{ inputs.enable_cache_dnf }}" == "true" ]]
then
cache="${cache} -v /cache/dnf:/cache/dnf"
fi
if [[ "${{ inputs.enable_cache_skopeo }}" == "true" ]]
then
cache="${cache} -v /cache/skopeo:/cache/skopeo"
fi
if [[ "${{ steps.load_dnf_cache.outputs.cache-hit }}" != "true" ]]
then
cache="${cache} -v /cache/dnf_new:/cache/dnf_new"
fi
vars=""
if [[ -n "${{ inputs.flatpak_remote_refs }}" ]] && [[ -n "${{ inputs.flatpak_remote_refs_dir }}" ]]
then
echo "ERROR: flatpak_remote_refs is mutually exclusive to flatpak_remote_refs_dir"
exit 1
else
if [[ -n "${{ inputs.flatpak_remote_refs }}" ]]
then
vars="${vars} FLATPAK_REMOTE_REFS=\"${{ inputs.flatpak_remote_refs }}\""
else
vars="${vars} FLATPAK_REMOTE_REFS_DIR=\"${{ inputs.flatpak_remote_refs_dir }}\""
fi
fi
docker run --privileged --volume ${{ github.workspace }}:/github/workspace/ ${cache} ${image}:${tag} \
ADDITIONAL_TEMPLATES="${{ inputs.additional_templates }}" \
ARCH="${{ inputs.arch }}" \
DNF_CACHE="/cache/dnf" \
ENROLLMENT_PASSWORD="${{ inputs.enrollment_password }}" \
FLATPAK_REMOTE_NAME="${{ inputs.flatpak_remote_name }}" \
${vars} \
FLATPAK_REMOTE_URL="${{ inputs.flatpak_remote_url }}" \
IMAGE_NAME="${{ inputs.image_name }}" \
IMAGE_REPO="${{ inputs.image_repo }}" \
IMAGE_TAG="${{ inputs.image_tag || inputs.version }}" \
SECURE_BOOT_KEY_URL="${{ inputs.secure_boot_key_url }}" \
VARIANT="${{ inputs.variant }}" \
VERSION="${{ inputs.version }}" \
WEB_UI="${{ inputs.web_ui }}"
- name: Save dnf cache
env:
dnf_cache_key: dnf-${{ inputs.version }}
if: inputs.enable_cache_dnf == 'true' && steps.load_dnf_cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: /cache/dnf_new
key: ${{ inputs.dnf_cache_key || env.dnf_cache_key }}
- name: Save skopeo cache
env:
skopeo_cache_key: skopeo-${{ inputs.image_name }}-${{ inputs.version || inputs.image_tag }}
if: inputs.enable_cache_skopeo == 'true' && steps.load_dnf_cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: /cache/skopeo
key: ${{ inputs.skopeo_cache_key || env.skopeo_cache_key }}
- name: Rename ISO file
id: rename_iso
shell: bash
run: |
if [[ ! ( "${{ inputs.iso_name }}" =~ \.iso$ ) ]]
then
iso_name="${{ inputs.iso_name }}.iso"
else
iso_name="${{ inputs.iso_name }}"
fi
if [[ "${{ inputs.iso_name }}" =~ ^/ ]]
then
full_path="${iso_name}"
else
full_path="${{ github.workspace }}/${iso_name}"
fi
mv ${{ github.workspace }}/build/deploy.iso ${full_path} || true
cd $(dirname ${full_path})
iso_fn=$(basename ${iso_name})
sha256sum ${iso_fn} > ${iso_fn}-CHECKSUM
echo "iso_path=${full_path}" >> $GITHUB_OUTPUT
echo "iso_name=${iso_fn}" >> $GITHUB_OUTPUT

View file

@ -2,19 +2,34 @@
set -ex set -ex
for entry in $@ # Create /dev/loop0 if it doesn't already exist. `losetup` has an issue creating it during the first run
mknod -m 0660 /dev/loop0 b 7 0 2>/dev/null || true
for i
do do
export $entry key=$(echo ${i} | cut -d= -f1)
value=$(echo ${i} | cut -d= -f2-)
export ${key}="${value}"
done done
if [[ -d /cache/skopeo ]]
then
ln -s /cache/skopeo /build-container-installer/container
fi
if [[ ! -d /cache/dnf ]]
then
mkdir /cache/dnf
fi
# Pull container # Pull container
make container/${IMAGE_NAME}-${IMAGE_TAG} $@ make container/${IMAGE_NAME}-${IMAGE_TAG} "$@"
# Build base ISO # Build base ISO
make boot.iso $@ make boot.iso "$@"
# Add container to ISO # Add container to ISO
make build/deploy.iso $@ make build/deploy.iso "$@"
# Make output dir in github workspace # Make output dir in github workspace
mkdir /github/workspace/build || true mkdir /github/workspace/build || true
@ -22,4 +37,3 @@ mkdir /github/workspace/build || true
# Copy resulting iso to github workspace and fix permissions # Copy resulting iso to github workspace and fix permissions
cp build/deploy.iso /github/workspace/build cp build/deploy.iso /github/workspace/build
chmod -R ugo=rwX /github/workspace/build chmod -R ugo=rwX /github/workspace/build

1
external/fedora-lorax-templates vendored Submodule

@ -0,0 +1 @@
Subproject commit cc1155372046baa58f9d2cc27a9e5473bf05a3fb

1
external/lorax vendored Submodule

@ -0,0 +1 @@
Subproject commit ffba3078beab843c5d663f6443dca28d8e820948

5
flatpak_refs/Firefox Normal file
View file

@ -0,0 +1,5 @@
app/org.mozilla.firefox/x86_64/stable
runtime/org.mozilla.firefox.Locale/x86_64/stable
runtime/org.freedesktop.Platform/x86_64/23.08
runtime/org.freedesktop.Platform.Locale/x86_64/23.08

2
flatpak_refs/VLC Normal file
View file

@ -0,0 +1,2 @@
app/org.videolan.VLC/x86_64/stable
runtime/org.kde.Platform/x86_64/5.15-23.08

View file

@ -0,0 +1,3 @@
<%page args="dnf_cache"/>
runcmd bash -c "if [[ -e ${dnf_cache}_new ]]; then cp -R ${dnf_cache}/* ${dnf_cache}_new/; fi"

View file

@ -0,0 +1,8 @@
<%page args="flatpak_remote_name, _flatpak_repo_url, version"/>
% if int(version) >= 41:
append etc/anaconda/conf.d/anaconda.conf "flatpak_remote = ${flatpak_remote_name} ${_flatpak_repo_url}"
% else:
replace "flatpak_manager\.add_remote\(\".*\", \".*\"\)" "flatpak_manager.add_remote(\"${flatpak_remote_name}\", \"${_flatpak_repo_url}\")" /usr/lib64/python*/site-packages/pyanaconda/modules/payloads/payload/rpm_ostree/flatpak_installation.py
replace "flatpak_manager\.replace_installed_refs_remote\(\".*\"\)" "flatpak_manager.replace_installed_refs_remote(\"${flatpak_remote_name}\")" /usr/lib64/python*/site-packages/pyanaconda/modules/payloads/payload/rpm_ostree/flatpak_installation.py
% endif

View file

@ -0,0 +1,4 @@
<%page args="image_name, image_tag"/>
append usr/share/anaconda/interactive-defaults.ks "ostreecontainer --url=/run/install/repo/${image_name}-${image_tag} --transport=oci --no-signature-verification"

View file

@ -0,0 +1,16 @@
<%page args="_flatpak_repo_gpg, flatpak_remote_name"/>
if [[ -d /ostree/deploy/default/var/lib/flatpak/repo ]]
then
echo ${_flatpak_repo_gpg} | base64 -d > /ostree/deploy/default/var/lib/flatpak/repo/flathub.trustedkeys.gpg
elif [[ -d /var/lib/flatpak/repo ]]
then
echo ${_flatpak_repo_gpg} | base64 -d > /var/lib/flatpak/repo/flathub.trustedkeys.gpg
else
echo "Could not find Flatpaks repo"
fi
if [[ "${flatpak_remote_name}" != 'fedora' ]]
then
systemctl disable flatpak-add-fedora-repos.service
fi

View file

@ -1,7 +1,7 @@
<%page args="image_repo, _image_repo_double_escaped, image_name, image_tag"/> <%page args="image_repo, _image_repo_double_escaped, image_name, image_tag, _rhel, version"/>
if (which bootc &> /dev/null) if (which bootc &> /dev/null) && [ ${_rhel} == 'false' && ${version} -ge 39 ]
then then
bootc switch ${image_repo}/${image_name}:${image_tag} bootc switch --mutate-in-place --enforce-container-sigpolicy --transport registry ${image_repo}/${image_name}:${image_tag}
else else
sed -i 's/container-image-reference=.*/container-image-reference=ostree-image-signed:docker:\/\/${_image_repo_double_escaped}\/${image_name}:${image_tag}/' /ostree/deploy/default/deploy/*.origin sed -i 's/container-image-reference=.*/container-image-reference=ostree-image-signed:docker:\/\/${_image_repo_double_escaped}\/${image_name}:${image_tag}/' /ostree/deploy/default/deploy/*.origin
fi fi

View file

@ -0,0 +1,26 @@
<%page args="enrollment_password"/>
## --nochroot
set -oue pipefail
readonly ENROLLMENT_PASSWORD=${enrollment_password}
readonly SECUREBOOT_KEY="/run/install/repo/sb_pubkey.der"
if [[ ! -d "/sys/firmware/efi" ]]; then
echo "EFI mode not detected. Skipping key enrollment."
exit 0
fi
if [[ ! -f "$SECUREBOOT_KEY" ]]; then
echo "Secure boot key not provided: $SECUREBOOT_KEY"
exit 0
fi
SYS_ID="$(cat /sys/devices/virtual/dmi/id/product_name)"
if [[ ":Jupiter:Galileo:" =~ ":$SYS_ID:" ]]; then
echo "Steam Deck hardware detected. Skipping key enrollment."
exit 0
fi
mokutil --timeout -1 || :
echo -e "$ENROLLMENT_PASSWORD\n$ENROLLMENT_PASSWORD" | mokutil --import "$SECUREBOOT_KEY" || :

View file

@ -1,2 +0,0 @@
append usr/share/anaconda/interactive-defaults.ks "ostreecontainer --url=/run/install/repo/${IMAGE_NAME}-${IMAGE_TAG} --transport=oci --no-signature-verification"

1
tests/iso/README.md Normal file
View file

@ -0,0 +1 @@
Place scripts that will test the ISO. The ISO file will be passed as the first argument

View file

@ -0,0 +1,37 @@
#!/bin/bash
add_line=$(grep flatpak_manager.add_remote /mnt/install/usr/lib64/python*/site-packages/pyanaconda/modules/payloads/payload/rpm_ostree/flatpak_installation.py)
add_line_repo=$(echo ${add_line} | grep ${FLATPAK_REMOTE_NAME})
add_line_url=$(echo ${add_line} | grep ${_FLATPAK_REPO_URL})
result=0
if [ -z "${add_line_repo}" ]
then
echo "Repo name not updated on add_remote line"
result=1
else
echo "Repo name found on add_remote line"
fi
if [ -z "${add_line_url}" ]
then
echo "Repo url not updated on add_remote line"
result=1
else
echo "Repo url found on add_remote line"
fi
replace_line=$(grep flatpak_manager.replace_installed_refs_remote /mnt/install/usr/lib64/python*/site-packages/pyanaconda/modules/payloads/payload/rpm_ostree/flatpak_installation.py)
replace_line_repo=$(echo ${replace_line} | grep ${FLATPAK_REMOTE_NAME})
if [ -z "${replace_line_repo}" ]
then
echo "Repo name not updated on replace_installed_refs line"
result=1
else
echo "Repo name found on replace_installed_refs line"
fi
exit ${result}

View file

@ -0,0 +1,14 @@
#!/bin/bash
FOUND_VERSION=$(cat /mnt/install/etc/os-release | grep VERSION_ID | cut -d= -f2)
if [[ ${FOUND_VERSION} != ${VERSION} ]]
then
echo "Version mismatch"
echo "Expected: ${VERSION}"
echo "Found: ${FOUND_VERSION}"
exit 1
else
echo "Correct version found"
exit 0
fi

39
tests/repo/vars.sh Normal file
View file

@ -0,0 +1,39 @@
#!/bin/bash
vars=()
while read -r line
do
if ! [[ $line =~ ^# ]]
then
vars+=$(echo $line | cut -d= -f1 | tr [:upper:] [:lower:])
fi
if [[ $line =~ ^########## ]]
then
break
fi
done < Makefile
result=0
for var in $vars
do
grep "^| ${var}" README.md > /dev/null
if [[ $? != 0 ]]
then
echo "$var not found in README.md"
result=1
fi
done
for var in $vars
do
grep "^ ${var}:" action.yml > /dev/null
if [[ $? != 0 ]]
then
echo "$var not found in action.yml"
result=1
fi
done
exit ${result}

1
tests/vm/README.md Normal file
View file

@ -0,0 +1 @@
Place scripts that will test the VM. The VM will be available at ${VM_IP} using username ${VM_USER} and password ${VM_PASS}

View file

@ -0,0 +1,16 @@
#!/usr/bin/env -S ansible-playbook -i ./ansible_inventory
---
- name: Test for installed flatpaks
hosts: vm
gather_facts: no
tasks:
- name: Collect facts about system services
service_facts:
register: services_state
- name: Check that flatpak-add-fedora-repos is disabled
ansible.builtin.assert:
that:
- services_state['ansible_facts']['services']['flatpak-add-fedora-repos.service']['status'] == 'disabled'
fail_msg: 'flatpak-add-fedora-repos.service is not disabled'

View file

@ -0,0 +1,25 @@
#!/usr/bin/env -S ansible-playbook -i ./ansible_inventory
---
- name: Test for installed flatpaks
hosts: vm
gather_facts: no
tasks:
# Verifies that the flatpaks are installed
- name: Get list of installed Flatpaks
become: true
ansible.builtin.command:
cmd: /usr/bin/flatpak list
register: flatpaks
- name: Check that VLC is installed
ansible.builtin.assert:
that:
- "'VLC' in flatpaks.stdout"
fail_msg: 'VLC is not installed'
- name: Check that Firefox is installed
ansible.builtin.assert:
that:
- "'Firefox' in flatpaks.stdout"
fail_msg: 'Firefox is not installed'

View file

@ -0,0 +1,12 @@
#!/usr/bin/env -S ansible-playbook -i ./ansible_inventory
---
- name: Test for flatpaks
hosts: vm
gather_facts: no
tasks:
# Verifies that the GPG key is functional
- name: Test updating flatpak packages
become: true
ansible.builtin.command:
cmd: /usr/bin/flatpak update -y --noninteractive

View file

@ -0,0 +1,25 @@
#!/usr/bin/env -S ansible-playbook -i ./ansible_inventory
---
- name: Test Container Image source updates
hosts: vm
gather_facts: no
tasks:
# Get list of origins
- name: Get origin
become: true
ansible.builtin.command:
cmd: /bin/bash -c "cat /ostree/deploy/default/deploy/*.origin"
register: origin
- name: Get vars
ansible.builtin.set_fact:
image_repo: "{{ lookup('ansible.builtin.env', 'IMAGE_REPO') }}"
image_name: "{{ lookup('ansible.builtin.env', 'IMAGE_NAME') }}"
image_tag: "{{ lookup('ansible.builtin.env', 'IMAGE_TAG') }}"
- name: Tests
ansible.builtin.assert:
that:
- (image_repo + '/' + image_name + ':' + image_tag) in origin.stdout
fail_msg: 'Origin not configured'

View file

@ -5,14 +5,20 @@ echo "-outdev $(pwd)/build/deploy.iso"
echo "-boot_image any replay" echo "-boot_image any replay"
echo "-joliet on" echo "-joliet on"
echo "-compliance joliet_long_names" echo "-compliance joliet_long_names"
if [ -f $(pwd)/sb_pubkey.der ]; then echo "-map $(pwd)/results/boot/grub2/grub.cfg boot/grub2/grub.cfg"
echo "-chmod 0444 boot/grub2/grub.cfg"
echo "-map $(pwd)/results/EFI/BOOT/grub.cfg EFI/BOOT/grub.cfg"
echo "-chmod 0444 EFI/BOOT/grub.cfg"
if [ -f $(pwd)/sb_pubkey.der ]
then
echo "-map $(pwd)/sb_pubkey.der sb_pubkey.der" echo "-map $(pwd)/sb_pubkey.der sb_pubkey.der"
echo "-chmod 0444 /sb_pubkey.der" echo "-chmod 0444 /sb_pubkey.der"
fi fi
echo "-map $(pwd)/scripts/enroll-secureboot-key.sh enroll-secureboot-key.sh"
echo "-chmod 0777 enroll-secureboot-key.sh"
pushd container > /dev/null pushd container > /dev/null
for file in $(find ${IMAGE_NAME}-${IMAGE_TAG}); do for file in $(find ${IMAGE_NAME}-${IMAGE_TAG})
do
echo "-map $(pwd)/${file} ${file}" echo "-map $(pwd)/${file} ${file}"
echo "-chmod 0444 ${file}" echo "-chmod 0444 ${file}"
done done