@ -1,12 +1,19 @@
.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
.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
all : help
help :
@echo
@echo "================================================"
@echo " Project ' $( PROJECT_NAME) ' "
@echo "================================================"
@echo
@echo "Relevant paths and settings:"
@echo
@echo " Configuration directory: /etc/quadlets/ $( PROJECT_NAME) "
@echo " Persistent Storage directory: /var/lib/quadlets/ $( PROJECT_NAME) "
@echo " UID & GID for project files: $( PROJECT_UID) : $( PROJECT_GID) "
@echo " Dependencies: $( if $( DEPENDENCIES) ,$( DEPENDENCIES) ,none) "
@echo
@echo "Available targets:"
@echo
@echo " help - Show this help message"
@echo " install - Install quadlets and systemd units"
@echo " uninstall - Uninstall quadlets and systemd units"
@ -15,43 +22,96 @@ help:
@echo " tail-logs - Tail the logs of the quadlet units"
@echo " butane - Build Butane specifications suitable for Fedora CoreOS"
@echo " fcos-vm - Launch a Fedora CoreOS VM with the generated Butane spec"
@echo " clean-vm - Clean up the Fedora CoreOS VM and its resources"
@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"
TARGET_CHROOT ?=
@echo
@echo "Useful commands:"
@echo
@echo " 1. make uninstall install # Replace quadlets and systemd units"
@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 " 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
@echo "All-in-one commands:"
@echo
@echo " 1. make I_KNOW_WHAT_I_AM_DOING=yes uninstall clean install tail-logs"
@echo " 2. make fcos-vm console"
@echo
# Create a temporary directory as target chroot when we detect that we are building Butane specs or launching a Fedora CoreOS VM.
i f n e q ( $( filter %.ign %.bu butane fcos -vm ,$ ( MAKECMDGOALS ) ) , )
i f e q ( $( TARGET_CHROOT ) , )
export TARGET_CHROOT := $( shell mktemp -d /tmp/butane-chroot-XXXXXX)
e n d i f
i f e q ( $( BUTANE_BLOCKLIST ) , )
export BUTANE_BLOCKLIST := $( shell tmp = $$ ( mktemp /tmp/butane-blocklist-XXXXXX) ; cp $( TOP_LEVEL_DIR) /butane.blocklist " $$ tmp " ; echo " $$ tmp " )
e n d i f
e n d i f
# Name of the current project, derived from the current working directory.
# This is used to create subdirectories for configuration and state files.
PROJECT_NAME := $( shell basename " $$ {PWD} " )
# Quadlets files and their corresponding systemd unit names
QUADLETS_FILES = $( wildcard *.container *.volume *.network *.pod *.build)
SYSTEMD_FILES = $( wildcard *.service *.target *.timer *.mount)
SYSTEMD_UNIT_NAMES := $( wildcard *.service *.target *.timer *.mount)
SYSTEMD_TIMER_NAMES := $( wildcard *.timer)
SYSTEMD_MAIN_UNIT_NAMES := $( wildcard *.target)
QUADLET_UNIT_NAMES := $( patsubst %.container, %.service, $( wildcard *.container) ) \
$( patsubst %.volume, %-volume.service, $( wildcard *.volume) ) \
$( patsubst %.network, %-network.service, $( wildcard *.network) ) \
$( patsubst %.pod, %-pod.service, $( wildcard *.pod) ) \
$( patsubst %.build, %-build.service, $( wildcard *.build) )
# Wellknown systemd unit file types
SYSTEMD_FILES = $( wildcard *.service *.target *.timer *.mount)
SYSTEMD_UNIT_NAMES := $( wildcard *.service *.target *.timer *.mount)
SYSTEMD_TIMER_NAMES := $( wildcard *.timer)
# The main systemd units will be enabled and started after installation.
SYSTEMD_MAIN_UNIT_NAMES := $( wildcard *.target)
# Configuration files
CONFIG_FILES = $( filter-out %/examples, $( wildcard config/*) )
TMPFILESD_FILES = $( filter-out %/examples, $( wildcard tmpfiles.d/*) )
SYSCTLD_FILES = $( filter-out %/examples, $( wildcard sysctl.d/*) )
EXAMPLES_CONFIG_FILES = $( wildcard config/examples/*)
EXAMPLES_TMPFILESD_FILES = $( wildcard tmpfiles.d/examples/*)
EXAMPLES_SYSCTLD_FILES = $( wildcard sysctl.d/examples/*)
TARGET_CONFIG_FILES = $( patsubst config/%, $( TARGET_CHROOT) /etc/quadlets/$( PROJECT_NAME) /%, $( CONFIG_FILES) )
TARGET_TMPFILESD_FILES = $( patsubst tmpfiles.d/%, $( TARGET_CHROOT) /etc/tmpfiles.d/%, $( TMPFILESD_FILES) )
TARGET_SYSCTLD_FILES = $( patsubst sysctl.d/%, $( TARGET_CHROOT) /etc/sysctl.d/%, $( SYSCTLD_FILES) )
# Example configuration files
EXAMPLES_CONFIG_FILES = $( wildcard config/examples/*)
EXAMPLES_TMPFILESD_FILES = $( wildcard tmpfiles.d/examples/*)
EXAMPLES_SYSCTLD_FILES = $( wildcard sysctl.d/examples/*)
TARGET_EXAMPLES_CONFIG_FILES = $( patsubst config/examples/%, $( TARGET_CHROOT) /etc/quadlets/$( PROJECT_NAME) /%, $( EXAMPLES_CONFIG_FILES) )
TARGET_EXAMPLES_TMPFILESD_FILES = $( patsubst tmpfiles.d/examples/%, $( TARGET_CHROOT) /etc/tmpfiles.d/%, $( EXAMPLES_TMPFILESD_FILES) )
TARGET_EXAMPLES_SYSCTLD_FILES = $( patsubst sysctl.d/examples/%, $( TARGET_CHROOT) /etc/sysctl.d/%, $( EXAMPLES_SYSCTLD_FILES) )
TARGET_EXAMPLE_FILES = $( TARGET_EXAMPLES_CONFIG_FILES) $( TARGET_EXAMPLES_TMPFILESD_FILES) $( TARGET_EXAMPLES_SYSCTLD_FILES)
# All configuration files to be installed
TARGET_FILES = $( addprefix $( TARGET_CHROOT) /etc/containers/systemd/, $( QUADLETS_FILES) ) \
$( addprefix $( TARGET_CHROOT) /etc/systemd/system/, $( SYSTEMD_FILES) ) \
$( TARGET_CONFIG_FILES) $( TARGET_TMPFILESD_FILES) $( TARGET_SYSCTLD_FILES)
# All example configuration files to be installed
TARGET_EXAMPLE_FILES = $( TARGET_EXAMPLES_CONFIG_FILES) $( TARGET_EXAMPLES_TMPFILESD_FILES) $( TARGET_EXAMPLES_SYSCTLD_FILES)
# Dependencies on other projects
# List here the names of other projects (directories at the top-level) that this project depends on.
DEPENDENCIES ?=
# Set this variable to "yes" to skip the confirmation prompt when running "make clean".
I_KNOW_WHAT_I_AM_DOING ?=
DEPENDENCIES_IGNITION_FILES = $( shell for dep in $( DEPENDENCIES) ; do echo $( TOP_LEVEL_DIR) /$$ dep/$$ dep.ign; done )
# 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 base $( DEPENDENCIES) ; do echo $( TOP_LEVEL_DIR) /$$ dep/$$ dep.ign $( TOP_LEVEL_DIR) /$$ dep/$$ dep-examples.ign; done )
# User and group IDs to own the project files and directories.
PROJECT_UID ?= 0
PROJECT_GID ?= 0
# Ensure that the Makefile is not run from the top-level directory and that it is run as root.
pre-requisites :
@if [ -z " $( TOP_LEVEL_DIR) " ] ; then \
echo "Do not run this Makefile from the top-level directory!" >& 2; \
@ -61,78 +121,95 @@ pre-requisites:
echo "This Makefile must be run as root" >& 2; \
exit 1; \
fi
@set -Eeuo pipefail; \
for tool in install systemctl systemd-analyze systemd-tmpfiles sysctl virt-install virsh qemu-img journalctl coreos-installer resize butane yq; do \
if ! which $$ tool & >/dev/null ; then \
echo " $$ tool is not installed. Please install it first. " >& 2; \
exit 1; \
fi ; \
done
# Perform a dry run of the podman systemd generator to validate the quadlet and systemd files.
dryrun :
QUADLET_UNIT_DIRS = " $$ PWD " /usr/lib/systemd/system-generators/podman-system-generator -dryrun > /dev/null
$(TARGET_CHROOT)/etc/containers/systemd :
install -D -d -m 0755 -o root -g root $@
$(TARGET_CHROOT)/etc/systemd/system :
# Create the base directories needed for installation.
$(TARGET_CHROOT)/etc/containers/systemd $(TARGET_CHROOT)/etc/systemd/system $(TARGET_CHROOT)/etc/tmpfiles.d $(TARGET_CHROOT)/etc/sysctl.d :
install -D -d -m 0755 -o root -g root $@
# Create the directory to store quadlet configuration files.
$(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME) :
install -D -d -m 0755 -o $( PROJECT_UID) -g $( PROJECT_GID) $@
$(TARGET_CHROOT)/etc/tmpfiles.d :
install -D -d -m 0755 -o root -g root $@
$(TARGET_CHROOT)/etc/sysctl.d :
install -D -d -m 0755 -o root -g root $@
# Copy quadlet files
$(TARGET_CHROOT)/etc/containers/systemd/% : % $( TARGET_CHROOT ) /etc /containers /systemd
install -m 0644 -o root -g root $< $@
# Copy systemd unit files
$(TARGET_CHROOT)/etc/systemd/system/% : % $( TARGET_CHROOT ) /etc /systemd /system
install -m 0644 -o root -g root $< $@
# Copy configuration files, handling executable and non-executable files differently.
$(TARGET_CONFIG_FILES) : $( TARGET_CHROOT ) /etc /quadlets /$( PROJECT_NAME ) /%: config /% $( TARGET_CHROOT ) /etc /quadlets /$( PROJECT_NAME )
$(TARGET_EXAMPLES_CONFIG_FILES) : $( TARGET_CHROOT ) /etc /quadlets /$( PROJECT_NAME ) /%: config /examples /% $( TARGET_CHROOT ) /etc /quadlets /$( PROJECT_NAME )
$(filter-out %.env, $(TARGET_CONFIG_FILES) $(TARGET_EXAMPLES_CONFIG_FILES)) :
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
if [ -x $< ] ; then \
run install -D -m 0755 -o $( PROJECT_UID) -g $( PROJECT_GID) $< $@ ; \
else \
run install -D -m 0644 -o $( PROJECT_UID) -g $( PROJECT_GID) $< $@ ; \
fi
# Handle .env files separately to set more restrictive permissions
$(filter %.env, $(TARGET_CONFIG_FILES) $(TARGET_EXAMPLES_CONFIG_FILES)) :
install -m 0600 -o root -g root -D $< $@
# Copy tmpfiles.d files
$(TARGET_TMPFILESD_FILES) : $( TARGET_CHROOT ) /etc /tmpfiles .d /%: tmpfiles .d /% $( TARGET_CHROOT ) /etc /tmpfiles .d
$(TARGET_EXAMPLES_TMPFILESD_FILES) : $( TARGET_CHROOT ) /etc /tmpfiles .d /%: tmpfiles .d /examples /% $( TARGET_CHROOT ) /etc /tmpfiles .d
$(TARGET_TMPFILESD_FILES) $(TARGET_EXAMPLES_TMPFILESD_FILES) :
install -D -m 0644 -o root -g root $< $@
# Copy sysctl.d files
$(TARGET_SYSCTLD_FILES) : $( TARGET_CHROOT ) /etc /sysctl .d /%: sysctl .d /% $( TARGET_CHROOT ) /etc /sysctl .d
$(TARGET_EXAMPLES_SYSCTLD_FILES) : $( TARGET_CHROOT ) /etc /sysctl .d /%: sysctl .d /examples /% $( TARGET_CHROOT ) /etc /sysctl .d
$(TARGET_SYSCTLD_FILES) $(TARGET_EXAMPLES_SYSCTLD_FILES) :
install -D -m 0644 -o root -g root $< $@
# Create the directory to store quadlet state and data.
$(TARGET_CHROOT)/var/lib/quadlets/$(PROJECT_NAME) :
install -d -m 0755 -o $( PROJECT_UID) -g $( PROJECT_GID) $@
# Copy all configuration files provided by this project.
install-config : $( TARGET_FILES ) $( TARGET_CHROOT ) /var /lib /quadlets /$( PROJECT_NAME )
# Copy all example configuration files provided by this project.
install-examples : $( TARGET_EXAMPLE_FILES ) $( TARGET_CHROOT ) /var /lib /quadlets /$( PROJECT_NAME )
# Copy all quadlets and systemd files provided by this project.
install-files : install -files -pre install -config install -examples
$( MAKE) install-files-post
# Custom commands to be run before copying quadlets and systemd files.
# This target can be extended by Makefiles sourcing this one.
install-files-pre ::
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
for dep in $( DEPENDENCIES) ; do \
run $( MAKE) -C $( TOP_LEVEL_DIR) /$$ dep install-files; \
done
install-files : install -files -pre install -config install -examples
$( MAKE) install-files-post
# Custom commands to be run after copying quadlets and systemd files.
# This target can be extended by Makefiles sourcing this one.
install-files-post ::
install-actions-pre ::
@run( ) { echo $$ *; " $$ @ " ; } ; \
for dep in $( DEPENDENCIES) ; do \
run $( MAKE) -C $( TOP_LEVEL_DIR) /$$ dep install-actions; \
done
# Perform post-installation actions such as enabling and starting units.
install-actions : install -actions -pre
systemctl daemon-reload
systemd-analyze --generators= true verify $( QUADLET_UNIT_NAMES) $( SYSTEMD_UNIT_NAMES)
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
if [ -f /etc/tmpfiles.d/$( PROJECT_NAME) .conf ] ; then \
run systemd-tmpfiles --create /etc/tmpfiles.d/$( PROJECT_NAME) .conf; \
fi ; \
@ -143,24 +220,39 @@ install-actions: install-actions-pre
systemctl start $( SYSTEMD_MAIN_UNIT_NAMES)
$( MAKE) install-actions-post
install-pre ::
install-post ::
# Custom commands to be run before performing post-installation actions.
# This target can be extended by Makefiles sourcing this one.
install-actions-pre ::
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
for dep in $( DEPENDENCIES) ; do \
run $( MAKE) -C $( TOP_LEVEL_DIR) /$$ dep install-actions; \
done
# Custom commands to be run after performing post-installation actions.
# This target can be extended by Makefiles sourcing this one.
install-actions-post ::
# Install all quadlets and systemd units provided by this project.
install : pre -requisites dryrun install -pre
$( MAKE) install-files
$( MAKE) install-actions
$( MAKE) install-post
uninstall-pre ::
uninstall-post ::
@run( ) { echo $$ *; " $$ @ " ; } ; \
for dep in $( DEPENDENCIES) ; do \
run $( MAKE) -C $( TOP_LEVEL_DIR) /$$ dep uninstall; \
done
# Custom commands to be run before installing quadlets and systemd units.
# This target can be extended by Makefiles sourcing this one.
install-pre ::
# Custom commands to be run after installing quadlets and systemd units.
# This target can be extended by Makefiles sourcing this one.
install-post ::
# Uninstall all quadlets and systemd units installed by this project.
uninstall : pre -requisites uninstall -pre
systemctl disable $( SYSTEMD_MAIN_UNIT_NAMES) $( SYSTEMD_TIMER_NAMES) || true
systemctl stop $( SYSTEMD_UNIT_NAMES) $( QUADLET_UNIT_NAMES) || true
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
if [ -f /etc/tmpfiles.d/$( PROJECT_NAME) .conf ] ; then \
run systemd-tmpfiles --purge /etc/tmpfiles.d/$( PROJECT_NAME) .conf; \
fi
@ -168,68 +260,94 @@ uninstall: pre-requisites uninstall-pre
systemctl daemon-reload
$( MAKE) uninstall-post
# Custom commands to be run before uninstalling quadlets and systemd units.
# This target can be extended by Makefiles sourcing this one.
uninstall-pre ::
# Custom commands to be run after uninstalling quadlets and systemd units.
# This target can be extended by Makefiles sourcing this one.
uninstall-post ::
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
for dep in $( DEPENDENCIES) ; do \
run $( MAKE) -C $( TOP_LEVEL_DIR) /$$ dep uninstall; \
done
# Tail the logs of all units managed by this project.
tail-logs : pre -requisites
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
declare -a journalctl_args = ( -f ) ; \
for unit in $$ ( $( MAKE) -s units 2>/dev/null | sort -u) ; do \
journalctl_args += ( -u " $$ unit " ) ; \
done ; \
run journalctl " $$ {journalctl_args[@]} "
$(PROJECT_NAME).bu : install -config
# Ensure that required variables are set before building Butane specifications.
butane-prerequisites :
@if [ -z " $( TARGET_CHROOT) " ] ; then \
echo "TARGET_CHROOT is not set!" ; exit 1; \
fi ; \
if [ -z " $( BUTANE_BLOCKLIST) " ] ; then \
echo "BUTANE_BLOCKLIST is not set!" ; exit 1; \
fi
$( TOP_LEVEL_DIR) /generate-butane-spec.sh $( TARGET_CHROOT) $( TOP_LEVEL_DIR) /butane.blocklist $( SYSTEMD_MAIN_UNIT_NAMES) $( SYSTEMD_TIMER_NAMES) > $( PROJECT_NAME) .bu
$(PROJECT_NAME)-examples.bu : install -examples
@if [ -z " $( TARGET_CHROOT) " ] ; then \
echo "TARGET_CHROOT is not set!" ; exit 1; \
fi
$( TOP_LEVEL_DIR) /generate-butane-spec.sh $( TARGET_CHROOT) butane.blocklist > $( PROJECT_NAME) -examples.bu
# Build the Butane specifications (configuration files) suitable for Fedora CoreOS.
# In order to avoid duplications in the ignition files, a blocklist is updated, containing file paths as they are added to the chroot.
$(PROJECT_NAME).bu : YQ_FILES := $( shell if [ -f "overlay .bu " ]; then echo "- overlay .bu "; else echo "-"; fi )
$(PROJECT_NAME).bu : butane -prerequisites install -config
$( TOP_LEVEL_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
@( cat $( TOP_LEVEL_DIR) /butane.blocklist; echo; for file in $$ ( find " $$ TARGET_CHROOT " ) ; do echo " $$ {file# $$ TARGET_CHROOT} " ; done ) | sort -u | grep -v -E '^$$' > " $( BUTANE_BLOCKLIST) "
# Build the Butane specifications (example files) suitable for Fedora CoreOS.
# In order to avoid duplications in the ignition files, a blocklist is updated, containing file paths as they are added to the chroot.
$(PROJECT_NAME)-examples.bu : butane -prerequisites install -examples
$( TOP_LEVEL_DIR) /generate-butane-spec.sh $( TARGET_CHROOT) $( BUTANE_BLOCKLIST) > $( PROJECT_NAME) -examples.bu
@( cat $( TOP_LEVEL_DIR) /butane.blocklist; echo; for file in $$ ( find " $$ TARGET_CHROOT " ) ; do echo " $$ {file# $$ TARGET_CHROOT} " ; done ) | sort -u | grep -v -E '^$$' > " $( BUTANE_BLOCKLIST) "
# Build the Butane specifications + Ignition files suitable for Fedora CoreOS of the dependencies of this project.
butane-pre :: butane -prerequisites
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
for dep in base $( DEPENDENCIES) ; do \
if [ [ " $$ dep " = = " $( PROJECT_NAME) " ] ] ; then \
# Avoid building the current project as its own dependency. \
continue ; \
fi ; \
run $( MAKE) -C $( TOP_LEVEL_DIR) /$$ dep $$ dep.ign $$ dep-examples.ign ; \
done
$(PROJECT_NAME).ign : butane
butane --strict -o $( PROJECT_NAME) .ign $( PROJECT_NAME) .bu
butane --strict -o $( PROJECT_NAME) -examples.ign $( PROJECT_NAME) -examples.bu
# Generate the current project's Ignition files from the Butane specs.
$(PROJECT_NAME).ign $(PROJECT_NAME)-examples.ign : butane -pre
$(PROJECT_NAME).ign $(PROJECT_NAME)-examples.ign : %.ign : %.bu
butane --strict -o $@ $<
butane :
@run( ) { echo $$ *; " $$ @ " ; } ; \
init_butane_blocklist( ) { \
( cat $( TOP_LEVEL_DIR) /butane.blocklist; echo; for file in $$ ( find " $$ TARGET_CHROOT " ) ; do echo " $$ {file# $$ TARGET_CHROOT} " ; done ) | sort -u | grep -v -E '^$$' > butane.blocklist; \
} ; \
if [ -z " $( TARGET_CHROOT) " ] ; then \
TARGET_CHROOT = $$ ( mktemp -d /tmp/butane-XXXXXX) ; \
else \
TARGET_CHROOT = " $( TARGET_CHROOT) " ; \
fi ; \
for dep in $( DEPENDENCIES) ; do \
run $( MAKE) -C $( TOP_LEVEL_DIR) /$$ dep TARGET_CHROOT = " $$ TARGET_CHROOT " butane ; \
done ; \
run init_butane_blocklist ; \
run $( MAKE) TARGET_CHROOT = " $$ TARGET_CHROOT " $( PROJECT_NAME) .bu; \
run init_butane_blocklist ; \
run $( MAKE) TARGET_CHROOT = " $$ TARGET_CHROOT " $( PROJECT_NAME) -examples.bu; \
if [ -z " $( TARGET_CHROOT) " ] ; then \
run rm -rf " $$ TARGET_CHROOT " ; \
fi
# Build the Butane specifications + Ignition files suitable for Fedora CoreOS, including those of the dependencies of this project.
butane : fcos .ign
# Generate the local Butane spec + Ignition file (the one containing local customizations).
$(TOP_LEVEL_DIR)/local.ign : $( TOP_LEVEL_DIR ) /local .bu
butane --strict -o $@ $<
# Because we don't know how to build this file, it is safer to declare it as phony and let the Makefile of the dependency handle it.
.PHONY : $( DEPENDENCIES_IGNITION_FILES )
# Build the ignition files of the dependencies of this project.
$(DEPENDENCIES_IGNITION_FILES) :
$( MAKE) -C $( dir $@ ) $( notdir $@ )
# The file might exist already, declare it as phony and let the child Makefile handle it.
.PHONY : $( DEPENDENCIES_IGNITION_FILES )
fcos.ign : fcos .bu $( TOP_LEVEL_DIR ) /local .ign $( PROJECT_NAME ) .ign $( DEPENDENCIES_IGNITION_FILES )
# Generate the final Fedora CoreOS ignition file by merging the Butane spec with the local and project-specific ignition files, as well as those of the dependencies.
fcos.ign : fcos .bu $( TOP_LEVEL_DIR ) /local .ign $( PROJECT_NAME ) .ign $( PROJECT_NAME ) -examples .ign $( DEPENDENCIES_IGNITION_FILES )
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
tmp = $$ ( mktemp -d /tmp/butane-XXXXXX) ; \
run cp $( filter %.ign,$^) $$ tmp; \
run butane --strict -d $$ tmp -o $@ fcos.bu; \
run rm -rf $$ tmp
# Fetch the latest version of the Fedora CoreOS QCOW2 image.
/var/lib/libvirt/images/library/fedora-coreos.qcow2 :
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
run mkdir -p /var/lib/libvirt/images/library/ ; \
if ! run coreos-installer download -p qemu -f qcow2.xz -d -C /var/lib/libvirt/images/library/ ; then \
echo "CoreOS QCOW2 image could not be downloaded." >& 2; \
@ -238,52 +356,87 @@ fcos.ign: fcos.bu $(TOP_LEVEL_DIR)/local.ign $(PROJECT_NAME).ign $(DEPENDENCIES_
qcow2 = $$ ( ls -1ctr /var/lib/libvirt/images/library/fedora-coreos-*.qcow2 | tail -n 1) ; \
run mv " $$ qcow2 " $@
# Copy the ignition file.
/var/lib/libvirt/images/fcos-$(PROJECT_NAME)/fcos.ign : fcos .ign
install -D -o root -g root -m 0644 $< $@
# Copy the Fedora CoreOS base image to create a new QCOW2 image for the VM.
/var/lib/libvirt/images/fcos-$(PROJECT_NAME)/root.qcow2 : /var /lib /libvirt /images /library /fedora -coreos .qcow 2
install -D -o root -g root -m 0644 $< $@
# Create an empty QCOW2 image for the /var filesystem of the VM.
/var/lib/libvirt/images/fcos-$(PROJECT_NAME)/var.qcow2 :
qemu-img create -f qcow2 $@ 100G
# Create the directory to be shared with the Fedora CoreOS VM through virtiofs.
/srv/fcos-$(PROJECT_NAME) :
install -d -o root -g root -m 0755 $@
fcos-vm : pre -requisites clean -vm /var /lib /libvirt /images /fcos -$( PROJECT_NAME ) /fcos .ign /var /lib /libvirt /images /fcos -$( PROJECT_NAME ) /root .qcow 2 /srv /fcos -$( PROJECT_NAME )
# Launch a Fedora CoreOS VM with the generated Butane spec.
fcos-vm : pre -requisites clean -vm /var /lib /libvirt /images /fcos -$( PROJECT_NAME ) /fcos .ign /var /lib /libvirt /images /fcos -$( PROJECT_NAME ) /root .qcow 2 /var /lib /libvirt /images /fcos -$( PROJECT_NAME ) /var .qcow 2 /srv /fcos -$( PROJECT_NAME )
virt-install --name= fcos-$( PROJECT_NAME) --import --noautoconsole \
--ram= 4096 --vcpus= 2 --os-variant= fedora-coreos-stable \
--disk path = /var/lib/libvirt/images/fcos-$( PROJECT_NAME) /root.qcow2,format= qcow2,size= 50 \
--disk path = /var/lib/libvirt/images/fcos-$( PROJECT_NAME) /var.qcow2,format= qcow2 \
--qemu-commandline= " -fw_cfg name=opt/com.coreos/config,file=/var/lib/libvirt/images/fcos- $( PROJECT_NAME) /fcos.ign " \
--network network = default,model= virtio \
--console= pty,target.type= virtio --serial= pty --graphics= none --boot= uefi \
--memorybacking= access.mode= shared,source.type= memfd \
--filesystem= type = mount,accessmode= passthrough,driver.type= virtiofs,driver.queue= 1024,source.dir= /srv/fcos-$( PROJECT_NAME) ,target.dir= data
# Clean up the Fedora CoreOS VM but keep its storage resources.
clean-vm : pre -requisites
virsh destroy fcos-$( PROJECT_NAME) || true
virsh undefine fcos-$( PROJECT_NAME) --nvram || true
rm -f /var/lib/libvirt/images/fcos-$( PROJECT_NAME) /root.qcow2 /var/lib/libvirt/images/fcos-$( PROJECT_NAME) /fcos.ign
# Remove all resources related to the Fedora CoreOS VM.
remove-vm : clean -vm
rm -rf /var/lib/libvirt/images/fcos-$( PROJECT_NAME)
rm -rf /srv/fcos-$( PROJECT_NAME)
# Connect to the console of the Fedora CoreOS VM.
console : pre -requisites
@while sleep 2; do virsh console fcos-$( PROJECT_NAME) ; echo -e "Disconnected. Reconnecting in 2 seconds...\nPress Ctrl-C to abort.\n" ; done
@set -Eeuo pipefail; \
# Save the current terminal size to restore it after disconnecting from the VM console. \
term_size = $$ ( stty size) ; \
while sleep 2; do \
virsh console fcos-$( PROJECT_NAME) ; \
# Restore the terminal size after disconnecting from the VM console. \
# This avoids issues with the terminal being stuck in an incorrect size because \
# the UEFI / Grub TUI messed with the terminal size during a VM reboot. \
eval $$ ( resize -s $$ term_size) ; \
echo -e "Disconnected. Reconnecting in 2 seconds...\nPress Ctrl-C to abort.\n" ; \
done
# List all systemd and quadlet unit names provided by the dependencies of this project.
units-pre ::
@for dep in $( DEPENDENCIES) ; do \
$( MAKE) -s -C $( TOP_LEVEL_DIR) /$$ dep units 2>/dev/null; \
done
# List all systemd and quadlet unit names provided by this project and, through "units-pre", also its dependencies.
units : units -pre
@for unit in $( SYSTEMD_UNIT_NAMES) $( QUADLET_UNIT_NAMES) ; do echo " $$ unit " ; done
# Custom commands to be run before cleaning persistent data and configuration files.
# This target can be extended by Makefiles sourcing this one.
clean-pre ::
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
for dep in $( DEPENDENCIES) ; do \
run $( MAKE) -C $( TOP_LEVEL_DIR) /$$ dep clean; \
done
# Custom commands to be run after cleaning persistent data and configuration files.
# This target can be extended by Makefiles sourcing this one.
clean-post ::
# Remove all persistent data and configuration files
clean : clean -pre pre -requisites
rm -f *.butane
rm -f $( PROJECT_NAME) { ,-examples} .bu *.ign butane.blocklist
@run( ) { echo $$ *; " $$ @ " ; } ; \
set -Eeuo pipefail; \
if [ " $( I_KNOW_WHAT_I_AM_DOING) " != "yes" ] ; then \
read -p " This will remove all data of ' $( PROJECT_NAME) '. Are you sure? (only 'yes' is accepted) " ans; \
if [ " $$ ans " != "yes" ] && [ " $$ ans " != "YES" ] ; then \
@ -292,3 +445,10 @@ clean: clean-pre pre-requisites
fi
rm -rf /var/lib/quadlets/$( PROJECT_NAME) / /var/run/quadlets/$( PROJECT_NAME) / /etc/quadlets/$( PROJECT_NAME) /
$( MAKE) clean-post
# 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 : 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 butane -prerequisites butane -pre