diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..e9e6834 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,16 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-dockerfile +{ + "name": "Existing Dockerfile", + // "build": { + // "context": "..", + // "dockerfile": "../Dockerfile", + // "args": { + // "version": "39" + // } + // }, + "image": "ghcr.io/jasonn3/build-container-installer:latest", + "overrideCommand": true, + "shutdownAction": "stopContainer", + "privileged": true +} \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..d446188 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Default owner of code within this repo +* @JasonN3 \ No newline at end of file diff --git a/.github/workflows/iso.yml b/.github/workflows/iso.yml index a0b0c6c..c912137 100644 --- a/.github/workflows/iso.yml +++ b/.github/workflows/iso.yml @@ -8,40 +8,13 @@ on: - 'v*' pull_request: - workflow_call: - inputs: - IMAGE_VERSION: - required: true - type: string - IMAGE_ARCH: - required: true - type: string - IMAGE_NAME: - required: true - type: string - IMAGE_REPO: - required: true - type: string - VARIANT: - required: true - type: string - BUILD_REPO: - required: false - type: string - default: JasonN3/container-installer - BUILD_REF: - required: false - type: string - default: main - +# Test Values env: - IMAGE_VERSION: ${{ inputs.IMAGE_VERSION || '39' }} - IMAGE_ARCH: ${{ inputs.IMAGE_ARCH || 'x86_64' }} - IMAGE_NAME: ${{ inputs.IMAGE_NAME || 'base-main' }} - IMAGE_REPO: ${{ inputs.IMAGE_REPO || 'ghcr.io/ublue-os' }} - VARIANT: ${{ inputs.VARIANT || 'Silverblue' }} - CURR_REPO: ${{ inputs.BUILD_REPO || github.repository }} - CURR_REF: ${{ inputs.BUILD_REF || github.ref }} + ARCH: 'x86_64' + IMAGE_NAME: 'base' + IMAGE_REPO: 'quay.io/fedora-ostree-desktops' + VERSION: '39' + VARIANT: 'Server' jobs: build-and-push-iso: @@ -53,58 +26,29 @@ jobs: contents: read packages: write steps: - - name: Install make and git - run: dnf install -y make git - - - name: Checkout repository - uses: actions/checkout@v4 - with: - repository: ${{ env.CURR_REPO }} - ref: ${{ env.CURR_REF }} - submodules: recursive - - - name: Install dependencies - run: make install-deps - - name: Lowercase Registry id: registry_case uses: ASzc/change-string-case-action@v6 with: string: ${{ env.IMAGE_REPO }} - - name: Download image - run: | - make container/${IMAGE_NAME}-${IMAGE_VERSION} \ - arch=${IMAGE_ARCH} \ - version=${IMAGE_VERSION} \ - image_repo=${{ steps.registry_case.outputs.lowercase }} \ - image_name=${IMAGE_NAME} \ - variant=${VARIANT} + - name: Build ISO + uses: ./ + with: + arch: ${{ env.ARCH}} + image_name: ${{ env.IMAGE_NAME}} + imagE_repo: ${{ env.IMAGE_REPO}} + version: ${{ env.VERSION }} + variant: ${{ env.VARIANT }} - - name: Create boot.iso + - name: Rename ISO run: | - make boot.iso \ - arch=${IMAGE_ARCH} \ - version=${IMAGE_VERSION} \ - image_repo=${{ steps.registry_case.outputs.lowercase }} \ - image_name=${IMAGE_NAME} \ - variant=${VARIANT} - - - name: Create deploy.iso - run: | - make ${IMAGE_NAME}-${IMAGE_VERSION}.iso \ - arch=${IMAGE_ARCH} \ - version=${IMAGE_VERSION} \ - image_repo=${{ steps.registry_case.outputs.lowercase }} \ - image_name=${IMAGE_NAME} \ - variant=${VARIANT} - mkdir end_iso - mv ${IMAGE_NAME}-${IMAGE_VERSION}.iso end_iso/ + mv build/deploy.iso ${{ env.IMAGE_NAME }}-${{ env.VERSION }}.iso - name: Upload ISO as artifact uses: actions/upload-artifact@v4 with: - name: ${{ env.IMAGE_NAME }}-${{ env.IMAGE_VERSION }}.iso + name: ${{ env.IMAGE_NAME }}-${{ env.VERSION }}.iso path: end_iso/*.iso if-no-files-found: error retention-days: 0 diff --git a/.gitignore b/.gitignore index 03894b9..53e679f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ /debugdata -/container +/build /pkglists /results /lorax_templates/*.tmpl @@ -8,5 +8,5 @@ /original-pkgsizes.txt /final-pkgsizes.txt /lorax.conf -/*.iso +/output /*.log \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c9175bc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM fedora:39 + +ARG VERSION=39 + +ENV ARCH="x86_64" +ENV IMAGE_NAME="base-main" +ENV IMAGE_REPO="ghcr.io/ublue-os" +ENV IMAGE_TAG="${VERSION}" +ENV VARIANT="Kinoite" +ENV VERSION="${VERSION}" +ENV WEB_UI="false" + +RUN mkdir /build-container-installer +COPY /lorax_templates /build-container-installer +COPY /xorriso /build-container-installer +COPY /Makefile /build-container-installer +COPY /entrypoint.sh / + +WORKDIR /build-container-installer + +RUN dnf install -y make && make install-deps + +VOLUME /build-container-installer/build + +ENTRYPOINT ["/bin/bash", "/entrypoint.sh"] \ No newline at end of file diff --git a/Makefile b/Makefile index d384476..01f118a 100644 --- a/Makefile +++ b/Makefile @@ -1,78 +1,96 @@ -arch = x86_64 -version = 39 -base_dir = $(shell pwd) -image_repo = ghcr.io/ublue-os -image_name = base-main -variant = Silverblue +# Configuration vars +## Formatting = UPPERCASE +ARCH = x86_64 +VERSION = 39 +IMAGE_REPO = ghcr.io/ublue-os +IMAGE_NAME = base-main +IMAGE_TAG = $(VERSION) +VARIANT = Kinoite +WEB_UI = false +VOL_ID = -image_repo_escaped = $(subst /,\/,$(image_repo)) -image_repo_double_escaped = $(subst \,\\\,$(image_repo_escaped)) +# Generated vars +## Formatting = _UPPERCASE +_BASE_DIR = $(shell pwd) +_IMAGE_REPO_ESCAPED = $(subst /,\/,$(IMAGE_REPO)) +_IMAGE_REPO_DOUBLE_ESCAPED = $(subst \,\\\,$(_IMAGE_REPO_ESCAPED)) +_VOLID = $(firstword $(subst -, ,$(IMAGE_NAME)))-$(ARCH)-$(IMAGE_TAG) -ifeq ($(variant),'Server') -lorax_args = --macboot --noupgrade +ifeq ($(VARIANT),'Server') +_LORAX_ARGS = --macboot --noupgrade else -lorax_args = --nomacboot +_LORAX_ARGS = --nomacboot endif -$(image_name)-$(version).iso: boot.iso container/$(image_name)-$(version) xorriso/input.txt - xorriso -dialog on < $(base_dir)/xorriso/input.txt +ifeq ($(WEB_UI),true) +_LORAX_ARGS += -i anaconda-webui +endif +# Step 6: Move end ISO +## Default action +build/deploy.iso.iso: boot.iso container/$(IMAGE_NAME)-$(IMAGE_TAG) xorriso/input.txt + mkdir $(_BASE_DIR)/build || true + xorriso -dialog on < $(_BASE_DIR)/xorriso/input.txt + +# Step 1: Generate Lorax Templates +lorax_templates/%.tmpl: lorax_templates/%.tmpl.in + sed 's/@IMAGE_NAME@/$(IMAGE_NAME)/' $(_BASE_DIR)/lorax_templates/$*.tmpl.in > $(_BASE_DIR)/lorax_templates/$*.tmpl + + sed 's/@IMAGE_TAG@/$(IMAGE_TAG)/' $(_BASE_DIR)/lorax_templates/$*.tmpl > $(_BASE_DIR)/lorax_templates/$*.tmpl.tmp + mv $(_BASE_DIR)/lorax_templates/$*.tmpl{.tmp,} + + sed 's/@IMAGE_REPO_ESCAPED@/$(_IMAGE_REPO_DOUBLE_ESCAPED)/' $(_BASE_DIR)/lorax_templates/$*.tmpl > $(_BASE_DIR)/lorax_templates/$*.tmpl.tmp + mv $(_BASE_DIR)/lorax_templates/$*.tmpl{.tmp,} + +# Step 2: Build boot.iso using Lorax boot.iso: lorax_templates/set_installer.tmpl lorax_templates/configure_upgrades.tmpl - rm -Rf $(base_dir)/results - lorax -p $(image_name) -v $(version) -r $(version) -t $(variant) \ - --isfinal --buildarch=$(arch) --volid=$(image_name)-$(arch)-$(version) \ - $(lorax_args) \ + rm -Rf $(_BASE_DIR)/results + lorax -p $(IMAGE_NAME) -v $(VERSION) -r $(VERSION) -t $(VARIANT) \ + --isfinal --buildarch=$(ARCH) --volid=$(_VOLID) \ + $(_LORAX_ARGS) \ --repo /etc/yum.repos.d/fedora.repo \ --repo /etc/yum.repos.d/fedora-updates.repo \ - --add-template $(base_dir)/lorax_templates/set_installer.tmpl \ - --add-template $(base_dir)/lorax_templates/configure_upgrades.tmpl \ - $(base_dir)/results/ - mv $(base_dir)/results/images/boot.iso $(base_dir)/ + --add-template $(_BASE_DIR)/lorax_templates/set_installer.tmpl \ + --add-template $(_BASE_DIR)/lorax_templates/configure_upgrades.tmpl \ + $(_BASE_DIR)/results/ + mv $(_BASE_DIR)/results/images/boot.iso $(_BASE_DIR)/ -container/$(image_name)-$(version): - mkdir container - podman pull $(image_repo)/$(image_name):$(version) - podman save --format oci-dir -o $(base_dir)/container/$(image_name)-$(version) $(image_repo)/$(image_name):$(version) - podman rmi $(image_repo)/$(image_name):$(version) +# Step 3: Download container image +container/$(IMAGE_NAME)-$(IMAGE_TAG): + mkdir container || true + podman pull $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) + podman save --format oci-dir -o $(_BASE_DIR)/container/$(IMAGE_NAME)-$(IMAGE_TAG) $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) + podman rmi $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) install-deps: dnf install -y lorax xorriso podman git rpm-ostree - - -lorax_templates/%.tmpl: lorax_templates/%.tmpl.in - sed 's/@IMAGE_NAME@/$(image_name)/' $(base_dir)/lorax_templates/$*.tmpl.in > $(base_dir)/lorax_templates/$*.tmpl - sed 's/@IMAGE_REPO@/$(image_repo_escaped)/' $(base_dir)/lorax_templates/$*.tmpl > $(base_dir)/lorax_templates/$*.tmpl.tmp - mv $(base_dir)/lorax_templates/$*.tmpl{.tmp,} - sed 's/@VERSION@/$(version)/' $(base_dir)/lorax_templates/$*.tmpl > $(base_dir)/lorax_templates/$*.tmpl.tmp - mv $(base_dir)/lorax_templates/$*.tmpl{.tmp,} - sed 's/@IMAGE_REPO_ESCAPED@/$(image_repo_double_escaped)/' $(base_dir)/lorax_templates/$*.tmpl > $(base_dir)/lorax_templates/$*.tmpl.tmp - mv $(base_dir)/lorax_templates/$*.tmpl{.tmp,} - - - -xorriso/input.txt: xorriso/gen_input.sh - bash $(base_dir)/xorriso/gen_input.sh | tee $(base_dir)/xorriso/input.txt - +# Step 4: Generate xorriso script xorriso/%.sh: xorriso/%.sh.in - sed 's/@IMAGE_NAME@/$(image_name)/' $(base_dir)/xorriso/$*.sh.in > $(base_dir)/xorriso/$*.sh - sed 's/@VERSION@/$(version)/' $(base_dir)/xorriso/$*.sh > $(base_dir)/xorriso/$*.sh.tmp - mv $(base_dir)/xorriso/$*.sh{.tmp,} - sed 's/@ARCH@/$(arch)/' $(base_dir)/xorriso/$*.sh > $(base_dir)/xorriso/$*.sh.tmp - mv $(base_dir)/xorriso/$*.sh{.tmp,} + sed 's/@IMAGE_NAME@/$(IMAGE_NAME)/' $(_BASE_DIR)/xorriso/$*.sh.in > $(_BASE_DIR)/xorriso/$*.sh + + sed 's/@IMAGE_TAG@/$(IMAGE_TAG)/' $(_BASE_DIR)/xorriso/$*.sh > $(_BASE_DIR)/xorriso/$*.sh.tmp + mv $(_BASE_DIR)/xorriso/$*.sh{.tmp,} + + sed 's/@ARCH@/$(ARCH)/' $(_BASE_DIR)/xorriso/$*.sh > $(_BASE_DIR)/xorriso/$*.sh.tmp + mv $(_BASE_DIR)/xorriso/$*.sh{.tmp,} + +# Step 5: Generate xorriso input +xorriso/input.txt: xorriso/gen_input.sh + bash $(_BASE_DIR)/xorriso/gen_input.sh | tee $(_BASE_DIR)/xorriso/input.txt clean: - rm -Rf $(base_dir)/container || true - rm -Rf $(base_dir)/debugdata || true - rm -Rf $(base_dir)/pkglists || true - rm -Rf $(base_dir)/results || true - rm -f $(base_dir)/lorax_templates/*.tmpl || true - rm -f $(base_dir)/xorriso/input.txt || true - rm -f $(base_dir)/xorriso/*.sh || true - rm -f $(base_dir)/{original,final}-pkgsizes.txt || true - rm -f $(base_dir)/lorax.conf || true - rm -f $(base_dir)/*.iso || true - rm -f $(base_dir)/*.log || true - + rm -Rf $(_BASE_DIR)/container || true + rm -Rf $(_BASE_DIR)/debugdata || true + rm -Rf $(_BASE_DIR)/pkglists || true + rm -Rf $(_BASE_DIR)/results || true + rm -f $(_BASE_DIR)/lorax_templates/*.tmpl || true + rm -f $(_BASE_DIR)/xorriso/input.txt || true + rm -f $(_BASE_DIR)/xorriso/*.sh || true + rm -f $(_BASE_DIR)/{original,final}-pkgsizes.txt || true + rm -f $(_BASE_DIR)/lorax.conf || true + rm -f $(_BASE_DIR)/*.iso || true + rm -f $(_BASE_DIR)/*.log || true +.PHONY: clean \ No newline at end of file diff --git a/README.md b/README.md index 8d1402b..a7e852e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,87 @@ -# container-installer -Creates an ISO for installing a container image as an OS +# Bulid Container Installer Action +This action is used to generate an ISO for installing OSTrees stored in a container. This utilizes the anaconda command `ostreecontainer` + +## Makefile +A Makefile is provided for ease of use. 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. + +See [Customizing](#customizing) for information about customizing the image that gets created. + +## Container +A container with the necessary tools already installed 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`. + +This will create an ISO with the baked in defaults of the container image. + +See [Customizing](#customizing) for information about customizing the image that gets created. The variable can either be defined as environment variables or as command arguments. +Examples: + +Building an ISO to install Fedora 38 +```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 +``` + +Building an ISO to install Fedora 39 +```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 +``` + +## Customizing +The following variables can be used to customize the create image. + +| Variable | Description | Default Value | +| ----------------- | -------------------------------------------------------- | ------------------------------ | +| ARCH | Architecture for image to build | x86_64 | +| VERSION | Fedora version of installer to build | 39 | +| IMAGE_REPO | Repository containing the source container image | quay.io/fedora-ostree-desktops | +| IMAGE_NAME | Name of the source container image | base | +| IMAGE_TAG | Tag of the source container image | *VERSION* | +| EXTRA_BOOT_PARAMS | Extra params used by grub to boot the anaconda installer | \[empty\] | +| VARIANT | Source container variant\* | Server | +| WEB_UI | Enable Anaconda WebUI (experimental) | false | + +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 + +## VSCode Dev Container +There is a dev container configuration provided for development. By default it will use the existing container image available at `ghcr.io/jasonn3/build-container-installer:latest`, however, you can have it build a new image by editing `.devcontainer/devcontainer.json` and replacing `image` with `build`. `Ctrl+/` can be used to comment and uncomment blocks of code within VSCode. + +The code from VSCode will be available at `/workspaces/build-container-installer` once the container has started. + +Privileged is required for access to loop devices for lorax. + +Use existing image +```json +{ + "name": "Existing Dockerfile", + // "build": { + // "context": "..", + // "dockerfile": "../Dockerfile", + // "args": { + // "version": "39" + // } + // }, + "image": "ghcr.io/jasonn3/build-container-installer:latest", + "overrideCommand": true, + "shutdownAction": "stopContainer", + "privileged": true +} +``` + +Build a new image +```json +{ + "name": "Existing Dockerfile", + "build": { + "context": "..", + "dockerfile": "../Dockerfile", + "args": { + "version": "39" + } + }, + //"image": "ghcr.io/jasonn3/build-container-installer:latest", + "overrideCommand": true, + "shutdownAction": "stopContainer", + "privileged": true +} +``` \ No newline at end of file diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..d57642f --- /dev/null +++ b/action.yml @@ -0,0 +1,43 @@ +name: Build Contianer Installer +description: generate an ISO for installing OSTrees stored in a container + +inputs: + arch: + description: Architecture for image to build + required: true + default: x86_64 + image_name: + description: Name of the source container image + required: true + default: base + image_repo: + description: Repository containing the source container image + required: true + default: quay.io/fedora-ostree-desktops + 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" + required: true + default: Server + version: + description: Fedora version of installer to build + required: true + default: "39" + image_tag: + description: Tag of the source container image. Defaults to the installer version + required: false + web_ui: + description: Enable Anaconda WebUI + required: true + default: "false" + +runs: + using: docker + image: 'Dockerfile' + args: + - ARCH=${{ inputs.arch }} + - IMAGE_NAME=${{ inputs.image_name }} + - IMAGE_REPO=${{ inputs.image_repo }} + - VARIANT=${{ inputs.variant }} + - VERSION=${{ inputs.version }} + - IMAGE_TAG=${{ inputs.image_tag }} + - WEB_UI=${{ inputs.web_ui }} diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..6de3b80 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -ex + +make container/${IMAGE_NAME}-${IMAGE_VERSION} $@ + +make boot.iso $@ + +make build/deploy.iso $@ + +mv build /github/workspace/ \ No newline at end of file diff --git a/lorax_templates/configure_upgrades.tmpl.in b/lorax_templates/configure_upgrades.tmpl.in index 2bbb92a..688cf79 100644 --- a/lorax_templates/configure_upgrades.tmpl.in +++ b/lorax_templates/configure_upgrades.tmpl.in @@ -1,3 +1,7 @@ append usr/share/anaconda/interactive-defaults.ks "%post --erroronfail" -append usr/share/anaconda/interactive-defaults.ks "sed -i 's/container-image-reference=.*/container-image-reference=ostree-image-signed:docker:\/\/@IMAGE_REPO_ESCAPED@\/@IMAGE_NAME@:@VERSION@/' /ostree/deploy/default/deploy/*.origin" -append usr/share/anaconda/interactive-defaults.ks "%end" \ No newline at end of file +append usr/share/anaconda/interactive-defaults.ks "sed -i 's/container-image-reference=.*/container-image-reference=ostree-image-signed:docker:\/\/@IMAGE_REPO_ESCAPED@\/@IMAGE_NAME@:@IMAGE_TAG@/' /ostree/deploy/default/deploy/*.origin" +append usr/share/anaconda/interactive-defaults.ks "%end" + +append usr/share/anaconda/post-scripts/configure_upgrades.ks "%post --erroronfail" +append usr/share/anaconda/post-scripts/configure_upgrades.ks "sed -i 's/container-image-reference=.*/container-image-reference=ostree-image-signed:docker:\/\/@IMAGE_REPO_ESCAPED@\/@IMAGE_NAME@:@IMAGE_TAG@/' /ostree/deploy/default/deploy/*.origin" +append usr/share/anaconda/post-scripts/configure_upgrades.ks "%end" \ No newline at end of file diff --git a/xorriso/gen_input.sh.in b/xorriso/gen_input.sh.in index 167e3b0..1df465b 100644 --- a/xorriso/gen_input.sh.in +++ b/xorriso/gen_input.sh.in @@ -3,7 +3,6 @@ echo "-indev $(pwd)/boot.iso" echo "-outdev $(pwd)/@IMAGE_NAME@-@VERSION@.iso" echo "-boot_image any replay" -echo "-volid @IMAGE_NAME@-@ARCH@-@VERSION@" echo "-joliet on" echo "-compliance joliet_long_names" cd container