From 5e70e2824c749a3667114166742eb26ec81d89ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Mass=C3=A9?= Date: Sat, 25 Apr 2026 15:18:09 +0000 Subject: [PATCH] generate tarball --- .gitignore | 1 + cookbooks/Makefile | 8 ++- scripts/cleanup-pytest-vm.sh | 17 ++++++ scripts/common.mk | 101 ++++++++++++++++++++++------------- scripts/generate-tarball.sh | 94 ++++++++++++++++++++++++++++++++ tests/fcos_vm.py | 6 +-- 6 files changed, 183 insertions(+), 44 deletions(-) create mode 100755 scripts/cleanup-pytest-vm.sh create mode 100755 scripts/generate-tarball.sh diff --git a/.gitignore b/.gitignore index 853c7f7..a107cdc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ !overlay.bu __pycache__/ .pytest_cache/ +**/build/*.tar.gz diff --git a/cookbooks/Makefile b/cookbooks/Makefile index 5a23302..cd75a41 100644 --- a/cookbooks/Makefile +++ b/cookbooks/Makefile @@ -1,14 +1,14 @@ SUBDIRS := $(wildcard */Makefile) SUBDIRS := $(dir $(SUBDIRS)) -.PHONY: all help butane clean dryrun fcos-vm clean-vm uninstall $(SUBDIRS) +.PHONY: all help package clean dryrun fcos-vm clean-vm uninstall $(SUBDIRS) export I_KNOW_WHAT_I_AM_DOING ?= no all: help help: @echo "Available targets:" - @echo " butane - Build Butane specifications suitable for Fedora CoreOS" + @echo " package - Package the quadlets and systemd units for distribution (Butane, Ignition, tarball, etc.)" @echo " clean - Remove the quadlets persistent data and configuration" @echo " dryrun - Perform a dry run of the podman systemd generator" @echo " fcos-vm - Launch a Fedora CoreOS VM with the generated Butane spec" @@ -16,11 +16,9 @@ help: @echo " uninstall - Uninstall the generated resources" @echo " pytest - Run integration tests on a clean Fedora CoreOS VM" - dryrun: $(SUBDIRS) -butane: $(SUBDIRS) +package: $(SUBDIRS) clean: $(SUBDIRS) - rm -f local.ign fcos-vm: $(SUBDIRS) clean-vm: $(SUBDIRS) diff --git a/scripts/cleanup-pytest-vm.sh b/scripts/cleanup-pytest-vm.sh new file mode 100755 index 0000000..c6e3115 --- /dev/null +++ b/scripts/cleanup-pytest-vm.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -u + +for vm in $(virsh list --name); do + virsh destroy $vm + virsh undefine --nvram $vm + rm -rf "/var/lib/libvirt/images/$vm" +done + +rm -rf /srv/pebble /srv/fcos-test-* +podman stop -i pebble-acme-server +podman rm -fi pebble-acme-server + +virsh net-dumpxml default | grep -oP '(?<=" --live --config +virsh net-destroy default +virsh net-start default diff --git a/scripts/common.mk b/scripts/common.mk index ae75c13..8516935 100644 --- a/scripts/common.mk +++ b/scripts/common.mk @@ -20,12 +20,13 @@ help: @echo " clean - Remove the quadlets persistent data and configuration" @echo " dryrun - Perform a dry run of the podman systemd generator" @echo " tail-logs - Tail the logs of the quadlet units" - @echo " butane - Build Butane specifications suitable for Fedora CoreOS" + @echo " package - Package the quadlets and systemd units for distribution (Butane, Ignition, tarball, etc.)" @echo " fcos-vm - Launch a Fedora CoreOS VM with the generated Butane spec" @echo " clean-vm - Clean up the Fedora CoreOS VM but keep its storage resources" @echo " remove-vm - Remove all resources related to the Fedora CoreOS VM" @echo " console - Connect to the Fedora CoreOS VM console" @echo " pytest - Run integration tests on a clean Fedora CoreOS VM" + @echo " debug - Dump makefile variables for debugging purposes" @echo @echo "Useful commands:" @echo @@ -33,10 +34,11 @@ help: @echo " 2. make uninstall clean install # Same but also remove persistent data and configuration" @echo " 3. make uninstall install tail-logs # Replace quadlets and systemd units, then tail their logs" @echo " 4. make I_KNOW_WHAT_I_AM_DOING=yes clean # Remove all persistent data and configuration without confirmation" - @echo " 5. make butane # Build Butane specifications suitable for Fedora CoreOS" + @echo " 5. make package # Package the quadlets and systemd units for distribution (Butane, Ignition, tarball, etc.)" @echo " 6. make fcos-vm console # Launch a fresh Fedora CoreOS VM (while retaining its persistent data) and connect to its console" @echo " 7. make remove-vm # Remove all resources related to the Fedora CoreOS VM" @echo " 8. make pytest # Run integration tests on a clean Fedora CoreOS VM" + @echo " 9. make debug | sort # Dump makefile variables for debugging purposes" @echo @echo "All-in-one commands:" @echo @@ -44,8 +46,13 @@ help: @echo " 2. make fcos-vm console" @echo +# Absolute paths derived from the location of this Makefile +SCRIPTS_DIR := $(shell realpath $(dir $(lastword $(MAKEFILE_LIST)))) +TOP_LEVEL_DIR := $(shell realpath $(SCRIPTS_DIR)/..) +COOKBOOKS_DIR := $(shell realpath $(TOP_LEVEL_DIR)/cookbooks) + # Create a temporary directory as target chroot when we detect that we are building Butane specs or launching a Fedora CoreOS VM. -ifneq ($(filter %.ign %.bu butane fcos-vm,$(MAKECMDGOALS)),) +ifneq ($(filter %.ign %.bu package fcos-vm,$(MAKECMDGOALS)),) ifeq ($(TARGET_CHROOT),) export TARGET_CHROOT := $(shell mktemp -d /tmp/butane-chroot-XXXXXX) endif @@ -61,11 +68,6 @@ endif # This is used to create subdirectories for configuration and state files. PROJECT_NAME := $(shell basename "$${PWD}") -# Absolute paths derived from the location of this Makefile -SCRIPTS_DIR := $(shell realpath $(dir $(lastword $(MAKEFILE_LIST)))) -TOP_LEVEL_DIR := $(shell realpath $(SCRIPTS_DIR)/..) -COOKBOOKS_DIR := $(shell realpath $(TOP_LEVEL_DIR)/cookbooks) - # Quadlets files and their corresponding systemd unit names QUADLETS_FILES = $(wildcard *.container *.volume *.network *.pod *.build *.image) QUADLET_UNIT_NAMES := $(patsubst %.container, %.service, $(wildcard *.container)) \ @@ -104,8 +106,8 @@ TARGET_EXAMPLES_SYSCTLD_FILES = $(patsubst sysctl.d/examples/%, $(TARGET_CHROOT) TARGET_EXAMPLES_PROFILED_FILES = $(patsubst profile.d/examples/%, $(TARGET_CHROOT)/etc/profile.d/%, $(EXAMPLES_PROFILED_FILES)) # Example quadlet and systemd drop-ins files -EXAMPLES_QUADLET_DROPINS_FILES := $(shell find examples -mindepth 1 -type f | grep -E '\.(container|volume|network|pod|build|image)\.d/' 2>/dev/null) -EXAMPLES_SYSTEMD_DROPINS_FILES := $(shell find examples -mindepth 1 -type f | grep -E '\.(service|target|timer|mount)\.d/' 2>/dev/null) +EXAMPLES_QUADLET_DROPINS_FILES := $(shell if [ -d examples ]; then find examples -mindepth 1 -type f | grep -E '\.(container|volume|network|pod|build|image)\.d/' 2>/dev/null; fi) +EXAMPLES_SYSTEMD_DROPINS_FILES := $(shell if [ -d examples ]; then find examples -mindepth 1 -type f | grep -E '\.(service|target|timer|mount)\.d/' 2>/dev/null; fi) TARGET_EXAMPLES_QUADLET_DROPINS_FILES = $(patsubst examples/%, $(TARGET_CHROOT)/etc/containers/systemd/%, $(EXAMPLES_QUADLET_DROPINS_FILES)) TARGET_EXAMPLES_SYSTEMD_DROPINS_FILES = $(patsubst examples/%, $(TARGET_CHROOT)/etc/systemd/system/%, $(EXAMPLES_SYSTEMD_DROPINS_FILES)) @@ -126,10 +128,10 @@ I_KNOW_WHAT_I_AM_DOING ?= # List of all ignition files corresponding to the dependencies # Here, we inject the "base" project as a dependency. It can therefore be assumed to always be embeddable in project's butane specs. -DEPENDENCIES_IGNITION_FILES := $(shell for dep in $$(if [ "$(PROJECT_NAME)" != "base" ]; then echo base; fi) $(DEPENDENCIES); do echo $(COOKBOOKS_DIR)/$$dep/$$dep.ign; done) +DEPENDENCIES_IGNITION_FILES := $(shell for dep in $$(if [ "$(PROJECT_NAME)" != "base" ]; then echo base; fi) $(DEPENDENCIES); do echo $(COOKBOOKS_DIR)/$$dep/build/$$dep.ign; done) # Variation of the previous variable with the built-in examples. -DEPENDENCIES_IGNITION_EXAMPLES_FILES := $(shell for dep in $$(if [ "$(PROJECT_NAME)" != "base" ]; then echo base; fi) $(DEPENDENCIES); do echo $(COOKBOOKS_DIR)/$$dep/$$dep.ign $(COOKBOOKS_DIR)/$$dep/$$dep-examples.ign; done) +DEPENDENCIES_IGNITION_EXAMPLES_FILES := $(shell for dep in $$(if [ "$(PROJECT_NAME)" != "base" ]; then echo base; fi) $(DEPENDENCIES); do echo $(COOKBOOKS_DIR)/$$dep/build/$$dep.ign $(COOKBOOKS_DIR)/$$dep/build/$$dep-examples.ign; done) # User and group IDs to own the project files and directories. PROJECT_UID ?= 0 @@ -139,6 +141,15 @@ PROJECT_GID ?= 0 HOOKS := $(wildcard $(COOKBOOKS_DIR)/*/hooks.mk) include $(HOOKS) +# Dump makefile variables for debugging purposes +debug: + $(foreach v, $(filter %_FILES SYSTEMD_% QUADLET% PROJECT_% DEPENDENCIES% %_DIR, $(.VARIABLES)), $(info $(v): $($(v)))) + @echo "TARGET_CHROOT: $(TARGET_CHROOT)" + @echo "BUTANE_BLOCKLIST: $(BUTANE_BLOCKLIST)" + @echo "BUTANE_START_TS: $(BUTANE_START_TS)" + @echo "HOOKS: $(HOOKS)" + @echo "I_KNOW_WHAT_I_AM_DOING: $(I_KNOW_WHAT_I_AM_DOING)" + # Ensure that the Makefile is run as root. pre-requisites:: @if [ "$$(id -u)" -ne 0 ]; then \ @@ -342,11 +353,18 @@ tail-logs: pre-requisites run journalctl "$${journalctl_args[@]}" pytest: pre-requisites - $(MAKE) butane + $(MAKE) package pytest tests/ +build: + mkdir -p build + # Build the Butane specifications, suitable for Fedora CoreOS, including those of the dependencies of this project. -$(PROJECT_NAME).bu $(PROJECT_NAME)-examples.bu &: +build/$(PROJECT_NAME).tar.gz build/$(PROJECT_NAME).bu build/$(PROJECT_NAME)-examples.bu: export PROJECT_NAME := $(PROJECT_NAME) +build/$(PROJECT_NAME).tar.gz build/$(PROJECT_NAME).bu build/$(PROJECT_NAME)-examples.bu: export TARGET_CHROOT := $(TARGET_CHROOT) +build/$(PROJECT_NAME).tar.gz build/$(PROJECT_NAME).bu build/$(PROJECT_NAME)-examples.bu: export BUTANE_BLOCKLIST := $(BUTANE_BLOCKLIST) +build/$(PROJECT_NAME).tar.gz build/$(PROJECT_NAME).bu build/$(PROJECT_NAME)-examples.bu: export SYSTEMD_MAIN_UNIT_NAMES := $(SYSTEMD_MAIN_UNIT_NAMES) +build/$(PROJECT_NAME).tar.gz build/$(PROJECT_NAME).bu build/$(PROJECT_NAME)-examples.bu &: @if [ -z "$(TARGET_CHROOT)" ]; then \ echo "TARGET_CHROOT is not set!"; exit 1; \ fi; \ @@ -357,55 +375,59 @@ $(PROJECT_NAME).bu $(PROJECT_NAME)-examples.bu &: echo "BUTANE_START_TS is not set!"; exit 1; \ fi @run() { echo $$*; "$$@"; }; \ + export ALL_DEPS="$(shell $(MAKE) -s list-dependencies 2>/dev/null)"; \ set -Eeuo pipefail; \ - if [ $(PROJECT_NAME).bu -ot "$(BUTANE_START_TS)" ] || [ $(PROJECT_NAME)-examples.bu -ot "$(BUTANE_START_TS)" ]; then \ + if [ build/$(PROJECT_NAME).bu -ot "$(BUTANE_START_TS)" ] || [ build/$(PROJECT_NAME)-examples.bu -ot "$(BUTANE_START_TS)" ]; then \ for dep in base $(DEPENDENCIES); do \ if [[ "$$dep" == "$(PROJECT_NAME)" ]]; then \ # Avoid building the current project as its own dependency. \ continue; \ fi ; \ - if [ $(BUTANE_START_TS) -ot "$(COOKBOOKS_DIR)/$$dep/$$dep.ign" ] && [ $(BUTANE_START_TS) -ot "$(COOKBOOKS_DIR)/$$dep/$$dep-examples.ign" ]; then \ + if [ $(BUTANE_START_TS) -ot "$(COOKBOOKS_DIR)/$$dep/build/$$dep.ign" ] && [ $(BUTANE_START_TS) -ot "$(COOKBOOKS_DIR)/$$dep/build/$$dep-examples.ign" ]; then \ # Dependency is up-to-date. \ continue; \ fi ; \ - run $(MAKE) -C $(COOKBOOKS_DIR)/$$dep $$dep.ign $$dep-examples.ign ; \ + run $(MAKE) -C $(COOKBOOKS_DIR)/$$dep build/$$dep.ign build/$$dep-examples.ign ; \ done; \ run make install-config; \ YQ_FILES="$$(if [ -f "overlay.bu" ]; then echo "- overlay.bu"; else echo "-"; fi)"; \ - echo "generate-butane-spec.sh $(TARGET_CHROOT) > $(PROJECT_NAME).bu"; \ - $(SCRIPTS_DIR)/generate-butane-spec.sh $(TARGET_CHROOT) $(BUTANE_BLOCKLIST) $(SYSTEMD_MAIN_UNIT_NAMES) $(SYSTEMD_TIMER_NAMES) | yq eval-all '. as $$item ireduce ({}; . *+ $$item)' $$YQ_FILES > $(PROJECT_NAME).bu; \ + echo "generate-butane-spec.sh $(TARGET_CHROOT) > build/$(PROJECT_NAME).bu"; \ + $(SCRIPTS_DIR)/generate-butane-spec.sh $(TARGET_CHROOT) $(BUTANE_BLOCKLIST) $(SYSTEMD_MAIN_UNIT_NAMES) $(SYSTEMD_TIMER_NAMES) | yq eval-all '. as $$item ireduce ({}; . *+ $$item)' $$YQ_FILES > build/$(PROJECT_NAME).bu; \ + $(SCRIPTS_DIR)/generate-tarball.sh build/$(PROJECT_NAME).tar.gz; \ (cat $(SCRIPTS_DIR)/butane.blocklist; echo; for file in $$(find "$$TARGET_CHROOT"); do echo "$${file#$$TARGET_CHROOT}"; done) | sort -u | grep -v -E '^$$' > "$(BUTANE_BLOCKLIST)"; \ run make install-examples; \ - echo "generate-butane-spec.sh $(TARGET_CHROOT) > $(PROJECT_NAME)-examples.bu"; \ - $(SCRIPTS_DIR)/generate-butane-spec.sh $(TARGET_CHROOT) $(BUTANE_BLOCKLIST) > $(PROJECT_NAME)-examples.bu; \ + echo "generate-butane-spec.sh $(TARGET_CHROOT) > build/$(PROJECT_NAME)-examples.bu"; \ + $(SCRIPTS_DIR)/generate-butane-spec.sh $(TARGET_CHROOT) $(BUTANE_BLOCKLIST) > build/$(PROJECT_NAME)-examples.bu; \ (cat $(SCRIPTS_DIR)/butane.blocklist; echo; for file in $$(find "$$TARGET_CHROOT"); do echo "$${file#$$TARGET_CHROOT}"; done) | sort -u | grep -v -E '^$$' > "$(BUTANE_BLOCKLIST)"; \ fi -.PHONY: $(PROJECT_NAME).bu $(PROJECT_NAME)-examples.bu +.PHONY: build/$(PROJECT_NAME).bu build/$(PROJECT_NAME)-examples.bu # Generate the current project's Ignition files from the Butane specs. -$(PROJECT_NAME).ign $(PROJECT_NAME)-examples.ign: %.ign: %.bu +build/$(PROJECT_NAME).ign build/$(PROJECT_NAME)-examples.ign: %.ign: %.bu build butane --strict -o $@ $< # Build the Butane specifications + Ignition files suitable for Fedora CoreOS, including those of the dependencies of this project. -butane: fcos-dev.ign fcos-test.ign +package: build/$(PROJECT_NAME).tar.gz build/fcos-dev.ign build/fcos-test.ign # Generate the local Butane spec + Ignition file (the one containing local customizations). -$(TOP_LEVEL_DIR)/local.ign: $(TOP_LEVEL_DIR)/local.bu +$(TOP_LEVEL_DIR)/build/local.ign: $(TOP_LEVEL_DIR)/local.bu + mkdir -p $(TOP_LEVEL_DIR)/build butane --strict -o $@ $< -.INTERMEDIATE: fcos-dev.bu fcos-test.bu +.INTERMEDIATE: build/fcos-dev.bu build/fcos-test.bu + # Generate the Butane specs for development and testing by merging the current project's spec with those of the dependencies. # The development spec also includes the examples of the dependencies. # Whereas the testing spec only includes the main specs of the dependencies. -fcos-dev.bu fcos-test.bu: DEPS := $(if $(filter-out base,$(PROJECT_NAME)),base $(DEPENDENCIES),$(DEPENDENCIES)) -fcos-dev.bu: DEPS := $(DEPS) $(addsuffix -examples,$(DEPS)) -fcos-dev.bu fcos-test.bu: %.bu: Makefile $(SCRIPTS_DIR)/default-butane-spec.sh +build/fcos-dev.bu build/fcos-test.bu: DEPS := $(if $(filter-out base,$(PROJECT_NAME)),base $(DEPENDENCIES),$(DEPENDENCIES)) +build/fcos-dev.bu: DEPS := $(DEPS) $(addsuffix -examples,$(DEPS)) +build/fcos-dev.bu build/fcos-test.bu: %.bu: Makefile $(SCRIPTS_DIR)/default-butane-spec.sh build $(SCRIPTS_DIR)/default-butane-spec.sh $(PROJECT_NAME) $(DEPS) > $@ # Generate the final Fedora CoreOS ignition files (dev & test) by merging the Butane spec with the local and project-specific ignition files, as well as those of the dependencies. -fcos-dev.ign: $(TOP_LEVEL_DIR)/local.ign $(PROJECT_NAME).ign $(PROJECT_NAME)-examples.ign $(DEPENDENCIES_IGNITION_EXAMPLES_FILES) -fcos-test.ign: $(TOP_LEVEL_DIR)/local.ign $(PROJECT_NAME).ign $(DEPENDENCIES_IGNITION_FILES) -fcos-dev.ign fcos-test.ign: fcos-%.ign: fcos-%.bu +build/fcos-dev.ign: $(TOP_LEVEL_DIR)/build/local.ign build/$(PROJECT_NAME).ign build/$(PROJECT_NAME)-examples.ign $(DEPENDENCIES_IGNITION_EXAMPLES_FILES) +build/fcos-test.ign: $(TOP_LEVEL_DIR)/build/local.ign build/$(PROJECT_NAME).ign $(DEPENDENCIES_IGNITION_FILES) +build/fcos-dev.ign build/fcos-test.ign: build/fcos-%.ign: build/fcos-%.bu build @run() { echo $$*; "$$@"; }; \ set -Eeuo pipefail; \ tmp=$$(mktemp -d /tmp/butane-XXXXXX); \ @@ -426,7 +448,7 @@ fcos-dev.ign fcos-test.ign: fcos-%.ign: fcos-%.bu run mv "$$qcow2" $@ # Copy the ignition file. -/var/lib/libvirt/images/fcos-$(PROJECT_NAME)/fcos.ign: fcos-dev.ign +/var/lib/libvirt/images/fcos-$(PROJECT_NAME)/fcos.ign: build/fcos-dev.ign install -D -o root -g root -m 0644 $< $@ # Copy the Fedora CoreOS base image to create a new QCOW2 image for the VM. @@ -488,6 +510,13 @@ units-pre:: units: units-pre @for unit in $(SYSTEMD_UNIT_NAMES) $(QUADLET_UNIT_NAMES); do echo "$$unit"; done +# List all dependencies of this project and also its transitive dependencies. +list-dependencies: + @for dep in $(DEPENDENCIES); do \ + echo "$$dep"; \ + $(MAKE) -s -C $(COOKBOOKS_DIR)/$$dep list-dependencies 2>/dev/null; \ + done | sort -u + # Custom commands to be run before cleaning persistent data and configuration files. # This target can be extended by Makefiles sourcing this one. clean-pre:: @@ -503,7 +532,7 @@ clean-post:: # Remove all persistent data and configuration files clean: clean-pre pre-requisites - rm -f $(PROJECT_NAME){,-examples}.bu *.ign butane.blocklist + rm -f build/$(PROJECT_NAME){,-examples}.bu build/*.ign @run() { echo $$*; "$$@"; }; \ set -Eeuo pipefail; \ if [ "$(I_KNOW_WHAT_I_AM_DOING)" != "yes" ]; then \ @@ -517,7 +546,7 @@ clean: clean-pre pre-requisites # All phony targets .PHONY: all install install-config install-examples uninstall pre-requisites clean dryrun -.PHONY: tail-logs butane help fcos-vm clean-vm console units units-pre remove-vm +.PHONY: tail-logs package help fcos-vm clean-vm console units units-pre remove-vm .PHONY: clean-pre clean-post install-pre install-post uninstall-pre uninstall-post .PHONY: install-files install-files-pre install-files-post install-actions -.PHONY: install-actions-pre install-actions-post pytest +.PHONY: install-actions-pre install-actions-post pytest list-dependencies debug diff --git a/scripts/generate-tarball.sh b/scripts/generate-tarball.sh new file mode 100755 index 0000000..f886a30 --- /dev/null +++ b/scripts/generate-tarball.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# This tool packages the current project as a tarball. +# +# The specification of the tarball is: +# - metadata.json: the project's metadata (name, dependencies, file list, unit names, etc.) +# - content.tar: the files to be installed on the target system, with their relative paths and permissions preserved. +# +# The tool takes its parameters from the environment variables defined in the Makefile: +# +# - PROJECT_NAME: the name of the project. +# - ALL_DEPS: the list of all (direct and transitive) dependencies of the project. +# - TARGET_CHROOT: the target chroot directory containing the files to be included in the tarball. +# - BUTANE_BLOCKLIST: the path to a file containing a list of files and directories (one per line) to ignore +# (i.e., files and directories that are already part of the CoreOS default installation +# or belonging to another package). +# - SYSTEMD_MAIN_UNIT_NAMES: the list of systemd main unit names to enable. +# +# The path to of the output tarball is $1. +# + +set -Eeuo pipefail + +# Create a temporary directory to store intermediate files (metadata.json and content.tar) +tmp_dir=$(mktemp -d) +trap 'rm -rf "$tmp_dir"' EXIT + +# Generate the file list from the TARGET_CHROOT, excluding files and directories in the BUTANE_BLOCKLIST +declare -a files_to_include=() +filelist_file="$tmp_dir/filelist.txt" +for path in $(find "$TARGET_CHROOT"); do + rel_path="${path#$TARGET_CHROOT}" + # Skip files & directories that are already part of the CoreOS default installation + if grep -qxF "$rel_path" "$BUTANE_BLOCKLIST"; then + continue + fi + + # Skip the root directory and empty paths + if [ -z "$rel_path" ] || [[ "$rel_path" == "/" ]]; then + continue + fi + + # The leading / is removed from the relative path in order for tar to find the file. + echo "${rel_path#/}" >> "$filelist_file" + + # Although, the absolute path is stored in the metadata file. + files_to_include+=("$rel_path") +done + +# Generate metadata.json +metadata_file="$tmp_dir/metadata.yaml" +cat < "$metadata_file" +name: $PROJECT_NAME +EOF +if [ -n "${ALL_DEPS}" ]; then + echo "dependencies:" >> "$metadata_file" + for dep in ${ALL_DEPS}; + do echo "- $dep" + done >> "$metadata_file" +else + echo "dependencies: []" >> "$metadata_file" +fi +if [ "${#files_to_include[@]}" -gt 0 ]; then + echo "files:" >> "$metadata_file" + for file in "${files_to_include[@]}"; do + echo "- $file" + done >> "$metadata_file" +else + echo "files: []" >> "$metadata_file" +fi +if [ -n "${SYSTEMD_MAIN_UNIT_NAMES}" ]; then + echo "systemd_main_units:" >> "$metadata_file" + for unit in ${SYSTEMD_MAIN_UNIT_NAMES}; do + echo "- $unit" + done >> "$metadata_file" +else + echo "systemd_main_units: []" >> "$metadata_file" +fi +# Convert metadata.yaml to metadata.json +yq -o json "$metadata_file" > "$tmp_dir/metadata.json" + +# Common tar options to ensure that the tarball is reproducible and does not contain unnecessary metadata +declare -a tar_options=( + "--no-selinux" + "--no-recursion" + "--no-xattrs" + "--no-acls" +) + +# Generate content.tar with the files to be included in the tarball, preserving their relative paths and permissions. +tar -cf "$tmp_dir/content.tar" "${tar_options[@]}" -C "$TARGET_CHROOT" --verbatim-files-from --files-from="$filelist_file" + +# Generate the final tarball. +tar -czf "$1" "${tar_options[@]}" -C "$tmp_dir" --owner=0 --group=0 metadata.json content.tar diff --git a/tests/fcos_vm.py b/tests/fcos_vm.py index 57225af..f8a0efc 100644 --- a/tests/fcos_vm.py +++ b/tests/fcos_vm.py @@ -31,11 +31,11 @@ FCOS_BASE_IMAGE = LIBVIRT_IMAGES_DIR / "library" / "fedora-coreos.qcow2" BUTANE_VERSION = "1.4.0" def ensure_fcos_ign(cookbook_dir: Path) -> Path: - """Return the path to fcos-test.ign, building it via ``make butane`` if absent.""" - fcos_ign = cookbook_dir / "fcos-test.ign" + """Return the path to fcos-test.ign, building it via ``make package`` if absent.""" + fcos_ign = cookbook_dir / "build" / "fcos-test.ign" if not fcos_ign.exists(): subprocess.run( - ["make", "-C", str(cookbook_dir), "butane"], + ["make", "-C", str(cookbook_dir), "package"], check=True, ) return fcos_ign