Last active
January 20, 2026 22:36
-
-
Save ianballou/9e38948de7b4e9064e6777cacfccd9a4 to your computer and use it in GitHub Desktop.
Default Foreman kickstart provisioning template for image mode machines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <%# | |
| kind: provision | |
| name: Kickstart Default bootc - Trimmed | |
| model: ProvisioningTemplate | |
| oses: | |
| - AlmaLinux | |
| - CentOS | |
| - CentOS_Stream | |
| - Fedora | |
| - RedHat | |
| - Rocky | |
| -%> | |
| <% | |
| # Variable setup for post scripts and container URL | |
| ostreecontainer = host_param('ostreecontainer') | |
| -%> | |
| # This kickstart file was rendered from the Foreman provisioning template "<%= @template_name %>". | |
| lang <%= host_param('lang') || 'en_US.UTF-8' %> | |
| selinux --<%= host_param('selinux-mode') || 'enforcing' %> | |
| keyboard <%= host_param('keyboard') || 'us' %> | |
| <% | |
| # Network setup is essential for pulling the container and reporting to Foreman | |
| @host.interfaces.reject{ |iface| iface.bmc? }.sort_by { |iface| (iface.bond? || iface.bridge?) ? 0 : iface.provision? ? 20 : 10 }.each do |iface| | |
| -%> | |
| <%= snippet( | |
| 'kickstart_network_interface', | |
| variables: { | |
| iface: iface, | |
| host: @host, | |
| static: @static, | |
| static6: @static6 | |
| } | |
| ) -%> | |
| <% | |
| end | |
| -%> | |
| # --- Core Installation --- | |
| # 1. Set the container image as the installation source | |
| ostreecontainer --url <%= ostreecontainer %> | |
| # 2. Set the root password to make the system login-able | |
| rootpw --iscrypted <%= root_pass %> | |
| # 3. Allow SSH for remote login | |
| firewall --service=ssh | |
| # --- Time --- | |
| timezone --utc <%= host_param('time-zone') || 'UTC' %> | |
| <% if host_param('ntp-pools') -%> | |
| <% host_param('ntp-pools').each do |ntppool| -%> | |
| timesource --ntp-pool <%= ntppool %> | |
| <% end -%> | |
| <% elsif host_param('ntp-server') -%> | |
| timesource --ntp-server <%= host_param('ntp-server') %> | |
| <% end -%> | |
| # --- Bootloader and Partitioning --- | |
| # This assumes you are assigning a partition table in Foreman. | |
| # For a modern bootc install, you might replace the bootloader/diskLayout | |
| # sections with: autopart --type=bootc | |
| bootloader --location=mbr --append="<%= host_param('bootloader-append') || 'nofb quiet splash=quiet' %>" <%= grub_pass %> | |
| <%= @host.diskLayout %> | |
| # --- Finalize --- | |
| text | |
| skipx | |
| reboot | |
| # --- Post-Install Scripts --- | |
| %post --nochroot | |
| exec < /dev/tty3 > /dev/tty3 | |
| chvt 3 | |
| ( | |
| <% if host_param_false?('no-resolv-override') -%> | |
| # Copy DNS configuration from installation environment | |
| cp -va /etc/resolv.conf /mnt/sysimage/etc/resolv.conf | |
| <% end -%> | |
| chvt 1 | |
| ) 2>&1 | tee /mnt/sysimage/root/install.postnochroot.log | |
| %end | |
| <%# | |
| This section injects SSH keys for Foreman, registers the system, | |
| and signals the build is done. | |
| %> | |
| %post | |
| exec < /dev/tty3 > /dev/tty4 | |
| chvt 3 | |
| ( | |
| # DNS should already be configured from %post --nochroot copy | |
| # But verify and recreate if missing (bootc containers may not have it) | |
| if [ ! -f /etc/resolv.conf ] || [ ! -s /etc/resolv.conf ]; then | |
| echo "WARNING: /etc/resolv.conf missing or empty in chroot, recreating from Foreman configuration" | |
| cat > /etc/resolv.conf << 'RESOLV_EOF' | |
| <% if @host.domain -%> | |
| search <%= @host.domain.name %> | |
| <% end -%> | |
| <% [@host.subnet.dns_primary, @host.subnet.dns_secondary].compact.each do |nameserver| -%> | |
| nameserver <%= nameserver %> | |
| <% end -%> | |
| RESOLV_EOF | |
| fi | |
| echo "=== DNS Configuration ===" | |
| cat /etc/resolv.conf | |
| echo "=== Testing DNS Resolution ===" | |
| nslookup cdn.redhat.com || echo "WARNING: Cannot resolve cdn.redhat.com" | |
| echo "==========================" | |
| <%= snippet 'redhat_register' -%> | |
| <%= snippet('remote_execution_ssh_keys') %> | |
| touch /tmp/foreman_built | |
| chvt 1 | |
| ) 2>&1 | tee /root/install.post.log | |
| %end | |
| <%# | |
| The last post section tells Foreman the build is complete. | |
| %> | |
| %post --erroronfail --log=/root/install-callhome.post.log | |
| if test -f /tmp/foreman_built; then | |
| echo "calling home: build is done!" | |
| <%= indent(2, skip1: true, skip_content: 'EOF') { snippet('built', :variables => { :endpoint => 'built', :method => 'POST', :body_body_file => '/root/install.post.log' }) } -%> | |
| else | |
| echo "calling home: build failed!" | |
| <%= indent(2, skip1: true, skip_content: 'EOF') { snippet('built', :variables => { :endpoint => 'failed', :method => 'POST', :body_body_file => '/root/install.post.log' }) } -%> | |
| fi | |
| sync | |
| %end |
Author
Author
The following template is working with subscription-manager registration. The key here was that DNS wasn't set up correctly in the system environment:
<%#
kind: provision
name: Kickstart Default bootc - Trimmed
model: ProvisioningTemplate
oses:
- AlmaLinux
- CentOS
- CentOS_Stream
- Fedora
- RedHat
- Rocky
-%>
<%
# Variable setup for post scripts and container URL
ostreecontainer = host_param('ostreecontainer')
-%>
# This kickstart file was rendered from the Foreman provisioning template "<%= @template_name %>".
lang <%= host_param('lang') || 'en_US.UTF-8' %>
selinux --<%= host_param('selinux-mode') || 'enforcing' %>
keyboard <%= host_param('keyboard') || 'us' %>
<%
# Network setup is essential for pulling the container and reporting to Foreman
@host.interfaces.reject{ |iface| iface.bmc? }.sort_by { |iface| (iface.bond? || iface.bridge?) ? 0 : iface.provision? ? 20 : 10 }.each do |iface|
-%>
<%= snippet(
'kickstart_network_interface',
variables: {
iface: iface,
host: @host,
static: @static,
static6: @static6
}
) -%>
<%
end
-%>
# --- Core Installation ---
# 1. Set the container image as the installation source
ostreecontainer --url <%= ostreecontainer %>
# 2. Set the root password to make the system login-able
rootpw --iscrypted <%= root_pass %>
# 3. Allow SSH for remote login
firewall --service=ssh
# --- Time ---
timezone --utc <%= host_param('time-zone') || 'UTC' %>
<% if host_param('ntp-pools') -%>
<% host_param('ntp-pools').each do |ntppool| -%>
timesource --ntp-pool <%= ntppool %>
<% end -%>
<% elsif host_param('ntp-server') -%>
timesource --ntp-server <%= host_param('ntp-server') %>
<% end -%>
# --- Bootloader and Partitioning ---
# This assumes you are assigning a partition table in Foreman.
# For a modern bootc install, you might replace the bootloader/diskLayout
# sections with: autopart --type=bootc
bootloader --location=mbr --append="<%= host_param('bootloader-append') || 'nofb quiet splash=quiet' %>" <%= grub_pass %>
<%= @host.diskLayout %>
# --- Finalize ---
text
skipx
reboot
# --- Post-Install Scripts ---
%post --nochroot
exec < /dev/tty3 > /dev/tty3
chvt 3
(
<% if host_param_false?('no-resolv-override') -%>
cp -va /etc/resolv.conf /mnt/sysimage/etc/resolv.conf
<% end -%>
# Hack to try fixing DNS
echo "search example.com" > /mnt/sysimage/etc/resolv.conf
echo "nameserver 192.168.73.1" >> /mnt/sysimage/etc/resolv.conf
chvt 1
) 2>&1 | tee /mnt/sysimage/root/install.postnochroot.log
%end
<%#
This section injects SSH keys for Foreman, registers the system,
and signals the build is done.
%>
%post
exec < /dev/tty3 > /dev/tty3
chvt 3
(
# Ensure DNS resolution works in chroot environment
cat > /etc/resolv.conf << 'EOF'
search example.com
nameserver 192.168.73.1
EOF
echo "=== DNS Configuration ==="
cat /etc/resolv.conf
echo "=== Testing DNS Resolution ==="
nslookup cdn.redhat.com || echo "WARNING: Cannot resolve cdn.redhat.com"
echo "=========================="
<%= snippet 'redhat_register' -%>
<%= snippet('remote_execution_ssh_keys') %>
touch /tmp/foreman_built
chvt 1
) 2>&1 | tee /root/install.post.log
%end
<%#
The last post section tells Foreman the build is complete.
%>
%post --erroronfail --log=/root/install-callhome.post.log
if test -f /tmp/foreman_built; then
echo "calling home: build is done!"
<%= indent(2, skip1: true, skip_content: 'EOF') { snippet('built', :variables => { :endpoint => 'built', :method => 'POST', :body_body_file => '/root/install.post.log' }) } -%>
else
echo "calling home: build failed!"
<%= indent(2, skip1: true, skip_content: 'EOF') { snippet('built', :variables => { :endpoint => 'failed', :method => 'POST', :body_body_file => '/root/install.post.log' }) } -%>
fi
sync
%end
Author
Latest KS template with /etc/resolv in chroot from the Foreman host:
<%#
kind: provision
name: Kickstart Default bootc - Trimmed
model: ProvisioningTemplate
oses:
- AlmaLinux
- CentOS
- CentOS_Stream
- Fedora
- RedHat
- Rocky
-%>
<%
# Variable setup for post scripts and container URL
ostreecontainer = host_param('ostreecontainer')
-%>
# This kickstart file was rendered from the Foreman provisioning template "<%= @template_name %>".
lang <%= host_param('lang') || 'en_US.UTF-8' %>
selinux --<%= host_param('selinux-mode') || 'enforcing' %>
keyboard <%= host_param('keyboard') || 'us' %>
<%
# Network setup is essential for pulling the container and reporting to Foreman
@host.interfaces.reject{ |iface| iface.bmc? }.sort_by { |iface| (iface.bond? || iface.bridge?) ? 0 : iface.provision? ? 20 : 10 }.each do |iface|
-%>
<%= snippet(
'kickstart_network_interface',
variables: {
iface: iface,
host: @host,
static: @static,
static6: @static6
}
) -%>
<%
end
-%>
# --- Core Installation ---
# 1. Set the container image as the installation source
ostreecontainer --url <%= ostreecontainer %>
# 2. Set the root password to make the system login-able
rootpw --iscrypted <%= root_pass %>
# 3. Allow SSH for remote login
firewall --service=ssh
# --- Time ---
timezone --utc <%= host_param('time-zone') || 'UTC' %>
<% if host_param('ntp-pools') -%>
<% host_param('ntp-pools').each do |ntppool| -%>
timesource --ntp-pool <%= ntppool %>
<% end -%>
<% elsif host_param('ntp-server') -%>
timesource --ntp-server <%= host_param('ntp-server') %>
<% end -%>
# --- Bootloader and Partitioning ---
# This assumes you are assigning a partition table in Foreman.
# For a modern bootc install, you might replace the bootloader/diskLayout
# sections with: autopart --type=bootc
bootloader --location=mbr --append="<%= host_param('bootloader-append') || 'nofb quiet splash=quiet' %>" <%= grub_pass %>
<%= @host.diskLayout %>
# --- Finalize ---
text
skipx
reboot
# --- Post-Install Scripts ---
%post --nochroot
exec < /dev/tty3 > /dev/tty3
chvt 3
(
<% if host_param_false?('no-resolv-override') -%>
# Copy DNS configuration from installation environment
cp -va /etc/resolv.conf /mnt/sysimage/etc/resolv.conf
<% end -%>
chvt 1
) 2>&1 | tee /mnt/sysimage/root/install.postnochroot.log
%end
<%#
This section injects SSH keys for Foreman, registers the system,
and signals the build is done.
%>
%post
exec < /dev/tty3 > /dev/tty4
chvt 3
(
# DNS should already be configured from %post --nochroot copy
# But verify and recreate if missing (bootc containers may not have it)
if [ ! -f /etc/resolv.conf ] || [ ! -s /etc/resolv.conf ]; then
echo "WARNING: /etc/resolv.conf missing or empty in chroot, recreating from Foreman configuration"
cat > /etc/resolv.conf << 'RESOLV_EOF'
<% if @host.domain -%>
search <%= @host.domain.name %>
<% end -%>
<% [@host.subnet.dns_primary, @host.subnet.dns_secondary].compact.each do |nameserver| -%>
nameserver <%= nameserver %>
<% end -%>
RESOLV_EOF
fi
echo "=== DNS Configuration ==="
cat /etc/resolv.conf
echo "=== Testing DNS Resolution ==="
nslookup cdn.redhat.com || echo "WARNING: Cannot resolve cdn.redhat.com"
echo "=========================="
<%= snippet 'redhat_register' -%>
<%= snippet('remote_execution_ssh_keys') %>
touch /tmp/foreman_built
chvt 1
) 2>&1 | tee /root/install.post.log
%end
<%#
The last post section tells Foreman the build is complete.
%>
%post --erroronfail --log=/root/install-callhome.post.log
if test -f /tmp/foreman_built; then
echo "calling home: build is done!"
<%= indent(2, skip1: true, skip_content: 'EOF') { snippet('built', :variables => { :endpoint => 'built', :method => 'POST', :body_body_file => '/root/install.post.log' }) } -%>
else
echo "calling home: build failed!"
<%= indent(2, skip1: true, skip_content: 'EOF') { snippet('built', :variables => { :endpoint => 'failed', :method => 'POST', :body_body_file => '/root/install.post.log' }) } -%>
fi
sync
%end
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here is a shortened version of the KS template. The firewall setting is back because I built firewalld into my container image (quay.io/iballou/rhel10-squid) and pushed it up. Note that it is still missing subscription registration - for some reason I keep hitting an error:
[Errno -2] Name or service not known.