Templates

The following functions and macros can be used within templates. These are guaranteed to work via the safemode rendering, to ensure a template can do nothing harmful. With safemode disabled other macros may work, but are not supported at this time.

To enable safemode, set "safemode_render" to "true" in Settings -> Foreman settings. Safemode rendering prevents templates from reading and writing files on the file system or modifying application data within foreman.

Accessing Templates

There are two ways to render a template, based on a single host, or based on a Hostgroup. The host or hostgroup provides all the details with which to render the template.

Host-based Rendering

Only a single template of each type may be rendered for a system. Foreman determines which template to use following these rules:

1. Only the templates of the appropriate kind and associated with the hosts operating system are considered
2. If a template has a hostgroup/environment combination that matches that of the host, use this template else
3. If a template is associated with the environment of the host, use this template, else
4. Use the first template found associated with the operating system associated with the host.

So essentially, the hostgroup/environment combination is used first, then just the environment, and finally just the operating system of the host.

To access a template of a certain type simply use this url:

/unattended/KIND_NAME

For example: /unattended/provision
would render the provisioning template. The host will be based on the IP Address it is accessed from. To spoof a template simply access the url in this manner:

/unattended/provision?spoof=192.168.0.1

where 192.168.0.1 is the ip address of the system you want to spoof. This allows you to view a template for a particular system from anywhere.

Hostgroup-based rendering

Allows any template to be rendered for any host group. When rendering using a hostgroup, @host is actually the hostgroup instead of a defined host. The default values for the hostgroup are used for templated values. This means if a value is not set in the hostgroup, you may get an error when rendering the template. To access a template using a Hostgroup to render, simply use this URL:

/unattended/template/Template Name/Hostgroup Name

For example, a hostgroup of name Finance, and a template named WebServerKickstart could be rendered using the url:

/unattended/template/WebServerKickstart/Finance

When building the default PXE template (from the Provisioning Templates page), any host group with the operating system, installation media and architecture set, plus provisioning templates with the host group set on the Associations tab will be listed at the bottom of the menu.

PXE Menus

PXE Menus can be deployed to smart proxies from the Provisioning Templates list page (/templates/provisioning_templates). All provisioning templates will be added with each of their hostgroup combinations (see above). For example if the template "WebServerKickstart" is associated to the Hostgroup1/Production, Hostgroup2/Production, and Hostgroup2/Testing combinations, the template would only be added twice. Once for WebServerKickstart-Hostgroup1 and WebServerKickstart-Hostgroup2.

Note that you can use only macros that are not host specific since this global PXE template is not specific to one host.

Writing templates

Templates can be written using common ERB style templating. Here's an example on using a variable/function:

@rootpw --iscrypted <%= root_pass %>@

Using a simple conditional:

@<%= "selinux --disabled\n" if @osver != 3 -%>@

This would include a line to disable selinux if the operating system version is not 3 (since Selinux isn't supported on RHEL 3)

Another way to do conditional (with if/elsif/else):

<% if @osver == 5 -%>
 echo "uses yum" 
<% elsif @osver == 4 -%>
 echo "uses up2date
<% else -%>
 echo "I'm not sure" 
<% end -%>

Functions and macros:

Generic macros

You should be able to use these macros in any template (Partition tables and Provisioning templates of all kinds)

Name Description Example
dns_lookup Performs a forward or reverse DNS lookup on a supplied name or IP address, Foreman 1.13+ echo <%= dns_lookup('example.com') %> example.com >> /etc/hosts
foreman_server_fqdn FQDN of Foreman server derived from foreman_url Setting, Foreman 1.12+ # Template generated at <%= foreman_server_fqdn %>
foreman_server_url Full URL of Foreman server equal to value of foreman_url Setting, Foreman 1.12+ curl <%= foreman_server_url %>/my_plugin_api
foreman_url(kind) Provides the full URL to a host-rendered template of the given kind, based on unattended_url Setting with fallback to current request headers foreman_url("provision") => http://HOST/unattended/provision
indent(n) Indents the block of code by n spaces, useful when using snippet which are not indented
<%= indent 4 do
    snippet 'subscription_manager_registration'
end %>
snippet(name) Renders the specified snippet
snippets(file) Renders the specified snippet found in DB, tries to load it from unattended/snippets/$file directory from hard drive it it's not found in DB
snippet_if_exists(name) Renders the specified snippet, skip it if it can't be found by name
template_name Returns @template_name (1.13+

Host specific macros

These macros can be used only when the template is rendered for specific host.

Name Description Example
grub_pass The GRUB password wrapped in md5pass argument grub_pass # => --md5pass=#{@host.grub_pass}
host_enc Returns the host's ENC hash of data, including lists of classes and parameters (Foreman 1.15+) <%= host_enc %>
host_param Returns the value of a parameter on the host, or inherited from a host group etc. (Foreman 1.15+) <%= host_param('example') %>
host_param_true? Returns true if the given host parameter is a true/yes/1 value (Foreman 1.15+) <% if host_param_true?('example') -%>
host_param_false? Returns true if the given host parameter is a false/no/0 value (Foreman 1.15+) <% if host_param_false?('example') -%>
ks_console A string assembled using the port and baud of the host which can be added to a kernel line ks_console # => console=ttyS1,9600
media_path not used anywhere in built in templates, candidate for removing in Foreman 1.13 media_path # => /media
root_pass The root password configured for the system

Remote Execution specific macros

Name Description Example
errata(<ID>) A hash of errata data containing errata_type, title, reboot_suggested & loads of others (Only applicable with Katello) errata(2) OR errata('RHBA-2016:1992')

Variables and snippets

Name Description Example
@host.model The name of the value assigned in Hardware Models. <% if @host.model.to_s == 'vmware' %> .. <% end -%>, <% if @host.model.to_s == 'xen' %> .. <% end -%>
@host.name The (full) name of the host
@host.shortname The (short) name of the host
@host.certname The SSL certificate name of the host
@host.domain The domain of the host
@host.ip The IPv4 address of the host
@host.ip6 The IPv6 address of the host
@host.hostgroup The hostgroup of the host <% if @host.hostgroup.to_s == "Base/Application Servers" -%>...<% end -%>
@host.mac The HW address of the host
@host.diskLayout The disklayout of the host (could come from the operating system)
@host.ptable The disklayout name <% if @host.ptable.name == 'Kickstart RHEL default' %> .. <% end %>
@host.puppetmaster The puppetmaster the host should use
@host.environment The environment the host should use
@host.location The location of the host
@host.architecture The arch of the host (i.e. x86_64)
@host.medium The assigned OS installation medium (1.10.2+)
@host.operatingsystem.name The operating system name
@host.operatingsystem.major The major version of the OS <% if @host.operatingsystem.major.to_i < 7 %> .. <% end %>
@host.operatingsystem.minor The minor version of the OS <% if @host.operatingsystem.minor.to_i > 2 %> .. <% end %>
@host.operatingsystem.family The OS Family (I.e. Redhat, Debian, etc.)
@host.os.medium_uri(@host) The url for provisioning (path configured in installation media) <%= @host.os.medium_uri(@host) %> => http://mirror.os.org/os/
@host.param_false?(name) returns false if host parameter of a given name evaluates to false (e.g. 0, 'no', false, 'false', 'f', off, nil) <%= @host.param_true?('enable-puppetlabs-repo') %> => true
@host.param_true?(name) returns true if host parameter of a given name evaluates to true (e.g. 1, 'yes', true, 'true', 't', on) <%= @host.param_true?('enable-puppetlabs-repo') %> => true
@host.subnet.mask The subnet mask of the host
@host.subnet.gateway The IPv4 gateway of the host
@host.subnet6.gateway The IPv6 gateway of the host
@host.subnet.dns_primary The primary DNS of the host
@host.subnet.dns_secondary The secondary DNS of the host
@host.subnet.dhcp Boolean that render true if a dhcp proxy is configured for this host <% if @host.subnet.dhcp %> .. <% else %> .. <% end %>
@host.url_for_boot(:kernel) Full url to the kernel associated with this host. Not recommended, as it doesn't interpolate variables, prefer boot_files_uri
@host.url_for_boot(:initrd) Full url to the initrd image associated with this host Not recommended, as it doesn't interpolate variables
@host.operatingsystem.boot_files_uri(@host.medium,@host.architecture) Full URL to the kernel and initrd, returns an array (1.10.2+)
@host.sp_name The name of the BMC interface
@host.sp_ip The IP address of the BMC interface
@host.sp_mac The HW address of the BMC interface
@host.sp_subnet Subnet of the BMC network
@host.interfaces Contains an array of all available host interfaces including primary (see networking notes below for changes between Foreman versions)
@host.primary_interface Returns host's primary interface (1.8+) it existed in 1.7, returning primary_interface identifier based on imported facts, 1.8+ it returns interface object
@host.provision_interface Returns host's provision interface (1.8+) returns interface object, see notes below for more details
@host.bond_interfaces Contains an array of all bonds (1.7+)
@host.managed_interfaces Limit the array to managed (non-BMC nor Bond) interfaces only which are set to be managed (1.7+)
@host.interfaces_with_identifier(['eth0', 'eth1']) Returns array of interfaces with given identifier (1.7+)
@host.interfaces.managed Limit the array to managed (non-BMC nor Bond) interfaces only (only works if safemode_render=false)
@host.interfaces.bmc Limit the array to BMC (non-managed) interfaces only (only works if safemode_render=false)
@host.interfaces.size Number of additional interfaces (either type interface or bmc) (only works if safemode_render=false) size=1 means a host has two interfaces on 1.7, one interface on 1.8+
@host.interfaces.empty If true host does not have ant interface (only works if safemode_render=false)
@host.facts Contains a hash of facts from Facter/Ohai etc. (1.7.2+)
@host.facts['ipaddress'] Accessing the 'ipaddress' fact for the host, use :: as a separator to access structured facts (1.7.2+)
@host.facts_hash Contains a hash of facts from Facter/Ohai etc. (only works if safemode_render=false)
@host.facts_hash['ipaddress'] Accessing the 'ipaddress' fact for the host (only works if safemode_render=false)
@host.image_build? Returns true if the host is provisioned using an image (1.5+) <% if @host.image_build? %>
@host.pxe_build? Returns true if the host is provisioned using the network/PXE (1.5+) <% if @host.pxe_build? %>
@provisioning_type Equal to 'host' or 'hostgroup' depending on type of provisioning (1.6+) <% if @provisioning_type == 'hostgroup' %>
@static Boolean value to determine if the network configuration is static or dynamic Use <%= @static ? "static" : "dynamic" %> in templates
@template_name Name of the template being rendered (1.7+) <%= @template_name %>

NOTE: For PXELinux templates in 0.4 or older only leave off the '@host.' from the above as it is currently generated slightly different from everything else.

NOTE: The interface array can be parsed this way:

<% @host.interfaces.each do |i| %> key is <%= i.ip %> <% end %>
. To print information for the first interface in the array, try something like:
<% myinterface = @host.interfaces.first %> IP: <%= myinterface.ip %> Netmask: <%= myinterface.subnet.mask %> Gateway: <%= myinterface.subnet.gateway %>

NOTE: Some variables can't be accessed while safemode is enabled. Disable via safemode_render in More > Settings, though be aware this enables arbitrary code to be added to templates. Some are being whitelisted via #2948.

NOTE: You may need to add "&static=yes" to the foreman_url to use the @static parameter in templates (see KickstartStatic).

NOTE: A lot of networking functions changed their meaning between 1.7 and 1.8 releases. In 1.7, primary interface used to be part of host object so it was not part of '@host.interfaces'. Also it could be detected by '@host.has_primary_interface?' which was removed in 1.8. For more advanced example of using networking functions, see kickstart_networking_setup.erb provisioning template snippet.

NOTE: If you get interface object as a returning value of some function (e.g. primary_interface or interfaces.first) it is evaluated to its DNS name by default. You can easily get to other attributes of such interface, e.g. @host.primary_interface.identifier or @host.primary_interface.mac. Valid attributes include: "managed?", "subnet" (returns subnet object), "virtual?", "physical?", "mac", "ip", "identifier", "attached_to", "link", "tag", "domain" (returns domain object), "vlanid", "bond_options", "attached_devices", "mode", "attached_devices_identifiers", "primary", "provision", "alias?", "inheriting_mac" (if it's virtual it inherits the mac from attached_to device)

Katello only Variables and snippets

Name Description Example
@host.info['parameters']['lifecycle_environment'] The lifecycle environment of the host
Katello::ActivationKey.find_by_name(@host.info['parameters']['kt_activation_keys']).host_collections[1]['name'] The first host collection in the activation key the host is using. (only works if safemode_render=false) <% if Katello::ActivationKey.find_by_name(@host.info['parameters']['kt_activation_keys').host_collections.select { |host_collection| host_collection['name'] == 'MY_HOST_COLLECTION_NAME' } -%>

Kickstart only variables (Only available for provision templates and "RedHat" Family operating systems):

Name Description Example
@osver The OS Major Version (Same as @host.operatingsystem.major)
@arch The architecture (same as @host.architecture.name)
@mediapath The full kickstart line to provide the url command. @mediapath => http://file.example.com/RHEL-5-Server/U5/x86_64/os/
@epel A command which will automatically install the correct version of the epel-release rpm. Use full in a %post script. @epel => "su -c 'rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm'"
@dynamic true if the parition table being used is a %pre script (has #Dynamic as the first line of the table) <% if @dynamic -%>

Preseed attributes (Only available for provision templates and "Debian" Family operating systems)::

Name Description Example
@preseed_path
@preseed_server

The values of those attributes are auto-computed based on the url attribute configured in the installation medium.

Host or host group parameters

In Foreman 1.15 or higher, retrieve the value of a parameter on a host (or inherited from the OS, domain etc) by using:

host_param('param_name')

In 1.14 or earlier:

@host.params['parameter_name']

If you need to test if a parameter contains a boolean true/false value, there are two helpers that will help:

host_param_true?('parameter_name')
host_param_false?('parameter_name')

Or on 1.14 or higher:

@host.param_true?('parameter_name')
@host.param_false?('parameter_name')

These check the parameter is a true/false/on/off/1/0 string.

Compute Resource Specific functions

see Compute Resources

Settings

Setting.setting_name

You will need to disable Safemode-Rendering in More->Settings.

Ruby methods

The most common methods on Ruby's core classes should be allowed (split, gsub, to_i, blank?, etc). A full list is in the Safemode Gem: https://github.com/svenfuchs/safemode/blob/master/lib/safemode/core_jails.rb#L33

To avoid turning off safemode, consider alternative ways of writing your ruby code. For example this would not work in the default Jail:

@host.ip.rpartition('.')[-1]

But this does:

@host.ip.split('.').last

Troubleshooting

Kickstart/preseed files are all generated dynamically based on the setting of each host in Foreman, things like partition tables and root password can be unique per server.

If you are having issues with a system building from a template or a system is unable to retrieve a template you can see the kickstart/preseed template result using your browser. If your system failed to retrieve the kickstart file it may be due to the fact that the template build failed.

Use the spoof parameter by pointing your browser to a url similar to:

http://foreman/unattended/provision?spoof=123.321.123.321
  • 123.321.123.321 is the hosts IP Address (the one you want to build).
  • usually you want to see the page source, the browser might display the file in html which will result in hard to read output.
  • the completed template will be displayed or any errors that were encountered while the template was being built.