Skip to content

Commit

Permalink
build_ostree_image
Browse files Browse the repository at this point in the history
Add ability to build an ostree image with `-e build_ostree_image -- $image_name`
  • Loading branch information
richm committed Sep 25, 2023
1 parent dedf507 commit d2d6d1a
Show file tree
Hide file tree
Showing 22 changed files with 2,715 additions and 1 deletion.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,33 @@ Older versions of `runqemu.py` would examine the `--image-name` or
`--image-file` value to determine if the image is an EL6 image, but this is now
deprecated. You must specify `--ssh-el6` if you need it.

### Building ostree images

Requirements: You will need to install the following packages to build and run:
osbuild-ostree osbuild-tools edk2-ovmf

tox-lsr can build images for [ostree](https://coreos.github.io/rpm-ostree/). The
`/usr` file system is read-only, which means the RPM packages and any other
files in `/usr` must be provided when the image is built. This means that the
system roles cannot actually manage (install, remove) packages on the system,
they can only verify that the required packages are available. You can use
`-e build_ostree_image -- $image_name` to build an ostree image for testing.
If you want to build for an image that is not supported by tox-lsr, download the
appropriate `$image_name.ipp.yml` into your `~/.config` directory. The image
will be available as `~/.cache/linux-system-roles/$image_name-ostree.qcow2` You
can test with the image like this:

```bash
TEST_USE_OVMF=true tox -e qemu-ansible-core-2.15 -- \
--image-file ~/.cache/linux-system-roles/fedora-38-ostree.qcow2 \
--log-level debug tests/tests_default.yml
```

#### .ostree directory

`build_ostree_image` uses the role `.ostree` directory to determine which
packages to build into the image.

### Container testing

Integration tests can be run using containers. `tox` will start one or
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"src/tox_lsr/test_scripts/lsr_ci_preinstall",
"src/tox_lsr/test_scripts/lsr_ci_runtox",
],
package_data={"": ["config_files/*", "test_scripts/*"]},
package_data={"": ["config_files/*", "test_scripts/*", "osbuild-manifests/**"]},
entry_points={
"tox": ["lsr = tox_lsr.hooks"],
},
Expand Down
12 changes: 12 additions & 0 deletions src/tox_lsr/config_files/tox-default.ini
Original file line number Diff line number Diff line change
Expand Up @@ -493,3 +493,15 @@ commands = bash {lsr_scriptdir}/setup_module_utils.sh
--output README.html README.md \
{env:RUN_CONVERT_README_EXTRA_ARGS:} {posargs}
{[lsr_config]commands_post}

[testenv:build_ostree_image]
changedir = {toxinidir}
allowlist_externals =
bash
cat
rm
make
sudo
setenv =
{[testenv]setenv}
commands = bash {lsr_scriptdir}/build_ostree_image.sh {posargs}
234 changes: 234 additions & 0 deletions src/tox_lsr/osbuild-manifests/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
NULL=
EMPTY :=
SPACE := $(EMPTY) $(EMPTY)
COMMA := ,
ESCAPEDSPACE := \$(SPACE)
ESCAPEDSPACE_REPLACEMENT := @@SPACE@@

# This is useful to handle space in forech rules
handle-escaped-space = $(subst $(ESCAPEDSPACE),$(ESCAPEDSPACE_REPLACEMENT),$1)
apply-escaped-space = $(subst $(ESCAPEDSPACE_REPLACEMENT),$(SPACE),$1)

HOST_ARCH:=$(shell arch)

ARCHES := x86_64 aarch64


export VM=0

OSBUILD_MPP=osbuild-mpp

DEFINES=
DEFINES_ARGS:=$(foreach def,$(call handle-escaped-space,$(DEFINES)),-D '$(call apply-escaped-space,$(def))')
MPP_ARGS=
export OSBUILD_ARGS=

BUILDDIR=_build
export STOREDIR=$(BUILDDIR)/osbuild_store
export OUTPUTDIR=$(BUILDDIR)/image_output

IMAGEDIR=
DESTDIR=.
EXTRA_DISTRO=

DISTROS := $(basename $(basename $(notdir f,$(wildcard distro/*.ipp.yml)))) $(if $(EXTRA_DISTRO),$(basename $(basename $(notdir $(EXTRA_DISTRO)))))
MANIFESTS := $(wildcard images/*.mpp.yml) $(foreach DIR,$(IMAGEDIR),$(wildcard $(DIR)/*))

EXTRA_MPP_ARGS= # For internal use
ifdef OSTREE_REPO
EXTRA_MPP_ARGS +=-D ostree_parent_refs='$(shell tools/ot-refs $(OSTREE_REPO))'
endif

export CHECKPOINTS=build
IMAGETYPES := regular ostree
FORMATS := img qcow2 oci.tar repo rootfs ext4 tar aboot
aarch64_TARGETS := ridesx4 rpi4 qdrive3 abootqemu
COMMON_TARGETS := qemu aws
HOST_TARGETS := $(COMMON_TARGETS) $($(HOST_ARCH)_TARGETS)
ALL_TARGETS := $(COMMON_TARGETS) $(foreach a,$(ARCHES), $($(a)_TARGETS))

manifest-get-name = $(basename $(basename $(notdir $1)))
manifest-get-dir = $(notdir $(patsubst %/,%,$(dir $1)))
image-name-noarch = $1-$3-$(call manifest-get-name,$2)-$4
image-name = $(call image-name-noarch,$1,$2,$3,$4).$5

# variable name for image type
regular_IMAGETYPE := regular
ostree_IMAGETYPE := ostree

help:
@echo
@echo This makefile is a wrapper around osbuild-mpp and osbuild to easily build images
@echo
@echo To build a raw image, run \"make image.img\", or to build a qcow2 image, run \"make image.qcow2\".
@echo This will build any image from a file called \"image.mpp.yml\" in the \"images\" subdirectory. You can
@echo pass IMAGEDIR=/some/other/path to make also to pick up manifests from an external directory.
@echo
@echo For example, to build a minimal qcow2 image with ostree support targeting qemu, run:
@echo ' make cs9-qemu-minimal-ostree.$(HOST_ARCH).qcow2'
@echo
@echo Other extensions are also supported:
@echo \ \* .repo: Generate a repo with an ostree commit \(only works for ostree targets\)
@echo \ \* .rootfs: Generate a directory with the rootfs content
@echo \ \* .tar: Generate a tar file with the rootfs content
@echo \ \* .ext4: Generate an ext4 filesystem with the rootfs content \(size from \"image_size\"\)
@echo \ \* .oci.tar: Generate an oci container image with the rootfs content
@echo \ \* .aboot: Generate an ext4 root filesystem and an android boot image \(for aboot targets\)
@echo
@echo You can pass variable declarations to osbuild-mpp with the DEFINES make variable.
@echo Multiple defines are separated by space, if you need a space inside a value escape it using \"\\ \".
@echo For example, to add extra rpms to a minimal regular image, use:
@echo " make cs9-qemu-minimal-regular.$(HOST_ARCH).qcow2 DEFINES='extra_rpms=[\"gdb\",\"strace\"]'"
@echo
@echo To easily run the image with qemu, you can use the included runvm tool, like:
@echo \ \ ./runvm cs9-qemu-minimal-regular.$(HOST_ARCH).qcow2
@echo
@echo There are some additional targets:
@echo \ \ manifests: generates resolved json manifests for all images without building them.
@echo \ \ clean_caches: Removes intermediate image build artifacts \(that improve rebuild speed\)
@echo \ \ clean_downloads: Removes files downloaded during image builds
@echo \ \ clean: Run clean_caches and clean_downloads
@echo \ \ osbuildvm-images: Build a image that can be used to build images inside a VM
@echo
@echo There are also some common conversion rules:
@echo \ \ foo.aboot.simg will build aboot.img / rootfs.img and convert rootfs.img using img2simg
@echo \ \ foo.ext4.simg will build foo.ext4 and then convert it with img2simg
@echo \ \ foo.simg will build foo.img and then convert it with img2simg
@echo \ \ foo.tar.gz will build $foo.tar and then gzip it
@echo
@echo "When building a custom variant of an image (say with an extra package) you can use a"
@echo custom @suffix to change the name of the produced file. For example:
@echo " make cs9-qemu-minimal-ostree@gdb.$(HOST_ARCH).qcow2 DEFINES='extra_rpms=[\"gdb\"]'"
@echo
@echo If you pass VM=1, then the images used from \"make osbuildvm-images\" will be used to do the
@echo actual building. This means that you don\'t need sudo rights to run osbuild, and it means
@echo architectures other than the current ones can be built.
@echo
@echo Available image targets can be listed with \"make list-targets\"
@echo

list-targets:
@echo Available image targets \(for $(HOST_ARCH)\) are:
@echo
@$(foreach d, $(DISTROS), $(foreach m, $(MANIFESTS), $(foreach t, $(HOST_TARGETS), $(foreach i,$(IMAGETYPES), echo -e " " $(call image-name,$d,$m,$t,$i,$(HOST_ARCH)).[$(subst $(SPACE),$(COMMA),$(FORMATS))];))))
@echo

# We pre-create all the toplevel dirs, so that they are owned by the user, not root (when created under sudo)
.PHONY: $(BUILDDIR)
$(BUILDDIR):
@mkdir -p $(BUILDDIR)
@mkdir -p $(STOREDIR)/{objects,refs,sources/org.osbuild.files,tmp}
@mkdir -p $(OUTPUTDIR)

# Template rule for producing osbuild json manifest from mpp yaml and image type
# $1 == distro name
# $2 == yaml manifest path
# $3 == Target name
# $4 == Image type
# $5 == Arch
define json-rule
$(BUILDDIR)/$(call image-name,$1,$2,$3,$4,$5).json: $2 $(BUILDDIR)
$(OSBUILD_MPP) -D $(if $(EXTRA_DISTRO),distro_dir="\"$(dir $(EXTRA_DISTRO))\"",distro_dir="\"distro\"") -I . -D image_type="\"$($4_IMAGETYPE)\"" -D arch=\"$5\" -D distro_name="\"$1\"" -D target="\"$3\"" $(DEFINES_ARGS) $(EXTRA_MPP_ARGS) $(MPP_ARGS) $$< $$@
.PHONY: $(BUILDDIR)/$(call image-name,$1,$2,$3,$4,$5).json
endef

$(foreach d, $(DISTROS), \
$(foreach m, $(MANIFESTS), \
$(foreach a,$(ARCHES), \
$(foreach t,$(COMMON_TARGETS) $($(a)_TARGETS), \
$(foreach i,$(IMAGETYPES), \
$(eval $(call json-rule,$d,$m,$t,$i,$a)))))))

# Template rule for producing image from json manifest
# $1 == distro name
# $2 == Manifest path
# $3 == Target
# $4 == Image type
# $5 == Arch
# $6 == Export format (extension)
define image-rule
$(call image-name,$1,$2,$3,$4,$5).$6: $(BUILDDIR)/$(call image-name,$1,$2,$3,$4,$5).json
@tools/runosbuild $(DESTDIR)/"$$@" "$$<" "$3" "$4" "$5" "$6"

$(call image-name-noarch,$1,$2,$3,$4)@%.$5.$6: $(BUILDDIR)/$(call image-name,$1,$2,$3,$4,$5).json
@tools/runosbuild $(DESTDIR)/"$$@" "$$<" "$3" "$4" "$5" "$6"
endef

$(foreach d, $(DISTROS), \
$(foreach m, $(MANIFESTS), \
$(foreach a,$(ARCHES), \
$(foreach t, $(COMMON_TARGETS) $($(a)_TARGETS), \
$(foreach f,$(FORMATS), \
$(foreach i,$(IMAGETYPES), \
$(eval $(call image-rule,$d,$m,$t,$i,$a,$f))))))))

# Rule to pre-generate all manifests
manifests: $(foreach d, $(DISTROS),$(foreach m, $(MANIFESTS), $(foreach a,$(ARCHES), $(foreach t, $(COMMON_TARGETS) $($(a)_TARGETS), $(foreach i,$(IMAGETYPES), $(BUILDDIR)/$(call image-name,$d,$m,$t,$i,$a).json)))))

define packages-rule
.PHONY: packages-$(call manifest-get-name,$1).json
packages-$(call manifest-get-name,$1).json: $1
osbuild-mpp $$< -D arch=\"x86_64\" - | jq -f tools/extract-rpms.jq > $$@.x86_64
osbuild-mpp $$< -D arch=\"aarch64\" - | jq -f tools/extract-rpms.jq > $$@.aarch64
echo 1 | jq --indent 4 -f tools/create-packagelist.jq --slurpfile x86_64 $$@.x86_64 --slurpfile aarch64 $$@.aarch64 > $$@
endef

$(foreach m, $(MANIFESTS), $(eval $(call packages-rule,$m)))

.PHONY: clean_downloads
clean_downloads:
sudo rm -rf _build/osbuild_store/sources/org.osbuild.files/*

.PHONY: clean_caches
clean_caches:
sudo rm -rf $(STOREDIR)/refs/*
sudo rm -rf $(STOREDIR)/refs_tars/*
sudo rm -rf $(STOREDIR)/objects/*
sudo rm -rf $(STOREDIR)/tmp/*
sudo rm -rf $(STOREDIR)/image_output/*

.PHONY: clean
clean: clean_downloads clean_caches

ifeq ($(VM), 1)
VM_SUDO=
VM_OSBUILD="osbuildvm/osbuildvm --arch=$(HOST_ARCH)"
else
VM_SUDO=sudo
VM_OSBUILD=sudo osbuild
endif

.PHONY: osbuildvm-images
osbuildvm-images: $(BUILDDIR)
osbuild-mpp osbuildvm/osbuildvm.mpp.yml _build/osbuildvm-$(HOST_ARCH).json
$(VM_OSBUILD) --store $(STOREDIR) --output-directory $(OUTPUTDIR) --export osbuildvm _build/osbuildvm-$(HOST_ARCH).json
cp $(OUTPUTDIR)/osbuildvm/disk.qcow2 _build/osbuildvm-$(HOST_ARCH).img
cp $(OUTPUTDIR)/osbuildvm/initramfs _build/osbuildvm-$(HOST_ARCH).initramfs
cp $(OUTPUTDIR)/osbuildvm/vmlinuz _build/osbuildvm-$(HOST_ARCH).vmlinuz
$(VM_SUDO) rm -rf $(OUTPUTDIR)/osbuildvm

%.aboot.simg : %.aboot
img2simg $</rootfs.img $</rootfs.simg
rm $</rootfs.img

%.ext4.simg : %.ext4
img2simg $< $@
rm $<

%.simg : %.img
img2simg $< $@
rm $<

%.tar.gz : %.tar
gzip -f $<

AUTOSIGREPO=https://mirror.stream.centos.org/SIGs/9-stream/automotive
define u-boot-rule
qemu-u-boot-$1.bin:
DLDIR=`mktemp -d` && \
dnf download -q --downloaddir $$$$DLDIR --disablerepo "*" --repofrompath "autosig,${AUTOSIGREPO}/$1/packages-main/" autosig-u-boot && \
rpm2cpio $$$$DLDIR/autosig-u-boot-*.rpm | cpio -id -D $$$$DLDIR && \
mv $$$$DLDIR/boot/u-boot.bin $$@ && \
rm -rf $$$$DLDIR
endef
$(foreach a,$(ARCHES), $(eval $(call u-boot-rule,$a)))
28 changes: 28 additions & 0 deletions src/tox_lsr/osbuild-manifests/distro/cs8.ipp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: '2'
mpp-vars:
distro_name: cs8
distro_version: 8
distro_baseurl: http://mirror.centos.org/centos/8-stream
distro_repos:
- id: baseos
baseurl: $distro_baseurl/BaseOS/$arch/os/
- id: appstream
baseurl: $distro_baseurl/AppStream/$arch/os/
- id: ha
baseurl: $distro_baseurl/HighAvailability/$arch/os/
- id: epel
baseurl: https://download.fedoraproject.org/pub/epel/$distro_version/Everything/$arch/
distro_devel_repos: []
distro_debug_repos: []
distro_module_id: platform:el8
kernel_package: kernel
release_rpm: centos-release # aka release_package
linux_firmware_rpm: linux-firmware
build_runner: org.osbuild.centos8
# dracut/initramfs stuff is not working on cs8
dracut_add_modules: ""
dracut_omit_modules: ""
dracut_filesystems: ""
dracut_add_drivers: ""
dracut_install: ""
rootfs_verity: false
20 changes: 20 additions & 0 deletions src/tox_lsr/osbuild-manifests/distro/cs9.ipp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: '2'
mpp-vars:
distro_name: cs9
distro_version: 9
distro_baseurl: http://mirror.stream.centos.org/9-stream
distro_baseurl_repo: $distro_baseurl/BaseOS/$arch/os/
distro_repos:
- id: baseos
baseurl: $distro_baseurl/BaseOS/$arch/os/
- id: appstream
baseurl: $distro_baseurl/AppStream/$arch/os/
- id: ha
baseurl: $distro_baseurl/HighAvailability/$arch/os/
distro_devel_repos: []
distro_debug_repos: []
distro_module_id: platform:el9
kernel_package: kernel
release_rpm: centos-release # aka release_package
linux_firmware_rpm: linux-firmware
build_runner: org.osbuild.centos9
19 changes: 19 additions & 0 deletions src/tox_lsr/osbuild-manifests/distro/f37.ipp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: '2'
mpp-vars:
distro_name: f37
osname: f37
uefi_vendor: fedora
distro_version: 37
distro_minor_version: 0
distro_baseurl: http://mirrors.kernel.org/fedora/releases/$distro_version/Everything/$arch/os
distro_repos:
- id: fedora
baseurl: http://mirrors.kernel.org/fedora/releases/$distro_version/Everything/$arch/os
- id: updates
baseurl: http://mirrors.kernel.org/fedora/updates/$distro_version/Everything/$arch
distro_devel_repos: []
distro_debug_repos: []
distro_module_id: platform:$distro_name
kernel_package: kernel
release_rpm: fedora-release # aka release_package
linux_firmware_rpm: linux-firmware
Loading

0 comments on commit d2d6d1a

Please sign in to comment.