Appendix A. Template Writing Reference
Embedded Ruby (ERB) is a tool for generating text files based on templates that combine plain text with Ruby code. Red Hat Satellite uses ERB syntax in the following cases:
- Provisioning templates
- For more information, see Creating Provisioning Templates in the Provisioning Guide.
- Remote execution job templates
- For more information, see Chapter 10, Configuring and Setting up Remote Jobs.
- Report templates
- For more information, see Chapter 8, Using Report Templates to Monitor Hosts.
- Templates for partition tables
- For more information, see Creating Partition Tables in the Provisioning Guide.
- Smart Variables
- For more information, see Configuring Smart Variables in the Puppet Guide.
- Smart Class Parameters
- For more information, see Configuring Smart Class Parameters in the Puppet Guide.
This section provides an overview of Satellite-specific macros and variables that can be used in ERB templates along with some usage examples. Note that the default templates provided by Red Hat Satellite (Hosts > Provisioning templates, Hosts > Job templates, Monitor > Report Templates ) also provide a good source of ERB syntax examples.
When provisioning a host or running a remote job, the code in the ERB is executed and the variables are replaced with the host specific values. This process is referred to as rendering. Satellite Server has the safemode rendering option enabled by default, which prevents any harmful code being executed from templates.
A.1. Accessing the Template Writing Reference in the Satellite web UI
You can access the template writing reference document in the Satellite web UI.
- Log in to the Satellite web UI.
- Navigate to Administer > About.
- Click the Templates DSL link in the Support section.
A.2. Writing ERB Templates
The following tags are the most important and commonly used in ERB templates:
<% %>
All Ruby code is enclosed within <% %>
in an ERB template. The code is executed when the template is rendered. It can contain Ruby control flow structures as well as Satellite-specific macros and variables. For example:
<% if @host.operatingsystem.family == "Redhat" && @host.operatingsystem.major.to_i > 6 -%> systemctl <%= input("action") %> <%= input("service") %> <% else -%> service <%= input("service") %> <%= input("action") %> <% end -%>
Note that this template silently performs an action with a service and returns nothing at the output.
<%= %>
This provides the same functionality as <% %>
but when the template is executed, the code output is inserted into the template. This is useful for variable substitution, for example:
Example input:
echo <%= @host.name %>
Example rendering:
host.example.com
Example input:
<% server_name = @host.fqdn %> <%= server_name %>
Example rendering:
host.example.com
Note that if you enter an incorrect variable, no output is returned. However, if you try to call a method on an incorrect variable, the following error message returns:
Example input:
<%= @example_incorrect_variable.fqdn -%>
Example rendering:
undefined method `fqdn' for nil:NilClass
<% -%>, <%= -%>
By default, a newline character is inserted after a Ruby block if it is closed at the end of a line:
Example input:
<%= "line1" %> <%= "line2" %>
Example rendering:
line1 line2
To change the default behavior, modify the enclosing mark with -%>
:
Example input:
<%= "line1" -%> <%= "line2" %>
Example rendering:
line1line2
This is used to reduce the number of lines, where Ruby syntax permits, in rendered templates. White spaces in ERB tags are ignored.
An example of how this would be used in a report template to remove unnecessary newlines between a FQDN and IP address:
Example input:
<%= @host.fqdn -%> <%= @host.ip -%>
Example rendering:
host.example.com10.10.181.216
<%# %>
Encloses a comment that is ignored during template rendering:
Example input:
<%# A comment %>
This generates no output.
Indentation in ERB templates
Because of the varying lengths of the ERB tags, indenting the ERB syntax might seem messy. ERB syntax ignore white space. One method of handling the indentation is to declare the ERB tag at the beginning of each new line and then use white space within the ERB tag to outline the relationships within the syntax, for example:
<%- load_hosts.each do |host| -%> <%- if host.build? %> <%= host.name %> build is in progress <%- end %> <%- end %>
A.3. Troubleshooting ERB Templates
The Satellite web UI provides two ways to verify the template rendering for a specific host:
- Directly in the template editor – when editing a template (under Hosts > Partition tables, Hosts > Provisioning templates, or Hosts > Job templates), on the Template tab click Preview and select a host from the list. The template then renders in the text field using the selected host’s parameters. Preview failures can help to identify issues in your template.
- At the host’s details page – select a host at Hosts > All hosts and click the Templates tab to list templates associated with the host. Select Review from the list next to the selected template to view it’s rendered version.
A.4. Generic Satellite-Specific Macros
This section lists Satellite-specific macros for ERB templates.
You can use the macros listed in the following table across all kinds of templates.
Name | Description |
---|---|
indent(n) | Indents the block of code by n spaces, useful when using a snippet template that is not indented. |
foreman_url(kind) | Returns the full URL to host-rendered templates of the given kind. For example, templates of the "provision" type usually reside at http://HOST/unattended/provision. |
snippet(name) | Renders the specified snippet template. Useful for nesting provisioning templates. |
snippets(file) | Renders the specified snippet found in the Foreman database, attempts to load it from the unattended/snippets/ directory if it is not found in the database. |
snippet_if_exists(name) | Renders the specified snippet, skips if no snippet with the specified name is found. |
A.5. Templates Macros
If you want to write custom templates, you can use some of the following macros.
Depending on the template type, some of the following macros have different requirements.
For more information about the available macros for report templates, in the Satellite web UI, navigate to Monitor > Report Templates, and click Create Template. In the Create Template window, click the Help tab.
For more information about the available macros for job templates, in the Satellite web UI, navigate to Hosts > Job Templates, and click the New Job Template. In the New Job Template window, click the Help tab.
- input
Using the
input
macro, you can customize the input data that the template can work with. You can define the input name, type, and the options that are available for users. For report templates, you can only use user inputs. When you define a new input and save the template, you can then reference the input in the ERB syntax of the template body.<%= input('cpus') %>
This loads the value from user input
cpus
.- load_hosts
Using the
load_hosts
macro, you can generate a complete list of hosts.<%- load_hosts().each_record do |host| -%> <%= host.name %>
Use the
load_hosts
macro with theeach_record
macro to load records in batches of 1000 to reduce memory consumption.If you want to filter the list of hosts for the report, you can add the option
search: input(‘Example_Host’)
:<% load_hosts(search: input('Example_Host')).each_record do |host| -%> <%= host.name %> <% end -%>
In this example, you first create an input that you then use to refine the search criteria that the
load_hosts
macro retrieves.- report_row
Using the
report_row
macro, you can create a formatted report for ease of analysis. Thereport_row
macro requires thereport_render
macro to generate the output.Example input:
<%- load_hosts(search: input('Example_Host')).each_record do |host| -%> <%- report_row( 'Server FQDN': host.name ) -%> <%- end -%> <%= report_render -%>
Example rendering:
Server FQDN host1.example.com host2.example.com host3.example.com host4.example.com host5.example.com host6.example.com
You can add extra columns to the report by adding another header. The following example adds IP addresses to the report:
Example input:
<%- load_hosts(search: input('host')).each_record do |host| -%> <%- report_row( 'Server FQDN': host.name, 'IP': host.ip ) -%> <%- end -%> <%= report_render -%>
Example rendering:
Server FQDN,IP host1.example.com,10.8.30.228 host2.example.com,10.8.30.227 host3.example.com,10.8.30.226 host4.example.com,10.8.30.225 host5.example.com,10.8.30.224 host6.example.com,10.8.30.223
- report_render
This macro is available only for report templates.
Using the
report_render
macro, you create the output for the report. During the template rendering process, you can select the format that you want for the report. YAML, JSON, HTML, and CSV formats are supported.<%= report_render -%>
- render_template()
This macro is available only for job templates.
Using this macro, you can render a specific template. You can also enable and define arguments that you want to pass to the template.
A.6. Host-Specific Variables
The following variables enable using host data within templates. Note that job templates accept only @host
variables.
Name | Description |
---|---|
@host.architecture | The architecture of the host. |
@host.bond_interfaces | Returns an array of all bonded interfaces. See Section A.9, “Parsing Arrays”. |
@host.capabilities | The method of system provisioning, can be either build (for example kickstart) or image. |
@host.certname | The SSL certificate name of the host. |
@host.diskLayout | The disk layout of the host. Can be inherited from the operating system. |
@host.domain | The domain of the host. |
@host.environment | The Puppet environment of the host. |
@host.facts | Returns a Ruby hash of facts from Facter. For example to access the 'ipaddress' fact from the output, specify @host.facts['ipaddress']. |
@host.grub_pass | Returns the host’s bootloader password. |
@host.hostgroup | The host group of the host. |
host_enc['parameters'] | Returns a Ruby hash containing information on host parameters. For example, use host_enc['parameters']['lifecycle_environment'] to get the life cycle environment of a host. |
@host.image_build? |
Returns |
@host.interfaces | Contains an array of all available host interfaces including the primary interface. See Section A.9, “Parsing Arrays”. |
@host.interfaces_with_identifier('IDs') | Returns array of interfaces with given identifier. You can pass an array of multiple identifiers as an input, for example @host.interfaces_with_identifier(['eth0', 'eth1']). See Section A.9, “Parsing Arrays”. |
@host.ip | The IP address of the host. |
@host.location | The location of the host. |
@host.mac | The MAC address of the host. |
@host.managed_interfaces | Returns an array of managed interfaces (excluding BMC and bonded interfaces). See Section A.9, “Parsing Arrays”. |
@host.medium | The assigned operating system installation medium. |
@host.name | The full name of the host. |
@host.operatingsystem.family | The operating system family. |
@host.operatingsystem.major | The major version number of the assigned operating system. |
@host.operatingsystem.minor | The minor version number of the assigned operating system. |
@host.operatingsystem.name | The assigned operating system name. |
@host.operatingsystem.boot_files_uri(medium_provider) | Full path to the kernel and initrd, returns an array. |
@host.os.medium_uri(@host) | The URI used for provisioning (path configured in installation media). |
host_param('parameter_name') | Returns the value of the specified host parameter. |
host_param_false?('parameter_name') |
Returns |
host_param_true?('parameter_name') |
Returns |
@host.primary_interface | Returns the primary interface of the host. |
@host.provider | The compute resource provider. |
@host.provision_interface | Returns the provisioning interface of the host. Returns an interface object. |
@host.ptable | The partition table name. |
@host.puppet_ca_server | The Puppet CA server the host must use. |
@host.puppetmaster | The Puppet master the host must use. |
@host.pxe_build? |
Returns |
@host.shortname | The short name of the host. |
@host.sp_ip | The IP address of the BMC interface. |
@host.sp_mac | The MAC address of the BMC interface. |
@host.sp_name | The name of the BMC interface. |
@host.sp_subnet | The subnet of the BMC network. |
@host.subnet.dhcp |
Returns |
@host.subnet.dns_primary | The primary DNS server of the host. |
@host.subnet.dns_secondary | The secondary DNS server of the host. |
@host.subnet.gateway | The gateway of the host. |
@host.subnet.mask | The subnet mask of the host. |
@host.url_for_boot(:initrd) | Full path to the initrd image associated with this host. Not recommended, as it does not interpolate variables. |
@host.url_for_boot(:kernel) | Full path to the kernel associated with this host. Not recommended, as it does not interpolate variables, prefer boot_files_uri. |
@provisioning_type | Equals to 'host' or 'hostgroup' depending on type of provisioning. |
@static |
Returns |
@template_name | Name of the template being rendered. |
grub_pass | Returns a bootloader argument to set the encrypted bootloader password, such as --md5pass=#{@host.grub_pass}. |
ks_console | Returns a string assembled using the port and the baud rate of the host which can be added to a kernel line. For example console=ttyS1,9600. |
root_pass | Returns the root password configured for the system. |
The majority of common Ruby methods can be applied on host-specific variables. For example, to extract the last segment of the host’s IP address, you can use:
<% @host.ip.split('.').last %>
A.7. Kickstart-Specific Variables
The following variables are designed to be used within kickstart provisioning templates.
Name | Description |
---|---|
@arch | The host architecture name, same as @host.architecture.name. |
@dynamic |
Returns |
@epel | A command which will automatically install the correct version of the epel-release rpm. Use in a %post script. |
@mediapath | The full kickstart line to provide the URL command. |
@osver | The operating system major version number, same as @host.operatingsystem.major. |
A.8. Conditional Statements
In your templates, you might perform different actions depending on which value exists. To achieve this, you can use conditional statements in your ERB syntax.
In the following example, the ERB syntax searches for a specific host name and returns an output depending on the value it finds:
Example input:
<% load_hosts().each_record do |host| -%>
<% if @host.name == "host1.example.com" -%>
<% result="positive" -%>
<% else -%>
<% result="negative" -%>
<% end -%>
<%= result -%>
Example rendering:
host1.example.com
positive
A.9. Parsing Arrays
While writing or modifying templates, you might encounter variables that return arrays. For example, host variables related to network interfaces, such as @host.interfaces
or @host.bond_interfaces
, return interface data grouped in an array. To extract a parameter value of a specific interface, use Ruby methods to parse the array.
Finding the Correct Method to Parse an Array
The following procedure is an example that you can use to find the relevant methods to parse arrays in your template. In this example, a report template is used, but the steps are applicable to other templates.
To retrieve the NIC of a content host, in this example, using the
@host.interfaces
variable returns class values that you can then use to find methods to parse the array.Example input:
<%= @host.interfaces -%>
Example rendering:
<Nic::Base::ActiveRecord_Associations_CollectionProxy:0x00007f734036fbe0>
-
In the Create Template window, click the Help tab and search for the
ActiveRecord_Associations_CollectionProxy
andNic::Base
classes. For
ActiveRecord_Associations_CollectionProxy
, in the Allowed methods or members column, you can view the following methods to parse the array:[] each find_in_batches first map size to_a
For
Nic::Base
, in the Allowed methods or members column, you can view the following method to parse the array:alias? attached_devices attached_devices_identifiers attached_to bond_options children_mac_addresses domain fqdn identifier inheriting_mac ip ip6 link mac managed? mode mtu nic_delay physical? primary provision shortname subnet subnet6 tag virtual? vlanid
To iterate through an interface array, add the relevant methods to the ERB syntax:
Example input:
<% load_hosts().each_record do |host| -%> <% host.interfaces.each do |iface| -%> iface.alias?: <%= iface.alias? %> iface.attached_to: <%= iface.attached_to %> iface.bond_options: <%= iface.bond_options %> iface.children_mac_addresses: <%= iface.children_mac_addresses %> iface.domain: <%= iface.domain %> iface.fqdn: <%= iface.fqdn %> iface.identifier: <%= iface.identifier %> iface.inheriting_mac: <%= iface.inheriting_mac %> iface.ip: <%= iface.ip %> iface.ip6: <%= iface.ip6 %> iface.link: <%= iface.link %> iface.mac: <%= iface.mac %> iface.managed?: <%= iface.managed? %> iface.mode: <%= iface.mode %> iface.mtu: <%= iface.mtu %> iface.physical?: <%= iface.physical? %> iface.primary: <%= iface.primary %> iface.provision: <%= iface.provision %> iface.shortname: <%= iface.shortname %> iface.subnet: <%= iface.subnet %> iface.subnet6: <%= iface.subnet6 %> iface.tag: <%= iface.tag %> iface.virtual?: <%= iface.virtual? %> iface.vlanid: <%= iface.vlanid %> <%- end -%>
Example rendering:
host1.example.com iface.alias?: false iface.attached_to: iface.bond_options: iface.children_mac_addresses: [] iface.domain: iface.fqdn: host1.example.com iface.identifier: ens192 iface.inheriting_mac: 00:50:56:8d:4c:cf iface.ip: 10.10.181.13 iface.ip6: iface.link: true iface.mac: 00:50:56:8d:4c:cf iface.managed?: true iface.mode: balance-rr iface.mtu: iface.physical?: true iface.primary: true iface.provision: true iface.shortname: host1.example.com iface.subnet: iface.subnet6: iface.tag: iface.virtual?: false iface.vlanid:
A.10. Example Template Snippets
Checking if a Host Has Puppet and Puppetlabs Enabled
The following example checks if the host has the Puppet and Puppetlabs repositories enabled:
<% pm_set = @host.puppetmaster.empty? ? false : true puppet_enabled = pm_set || host_param_true?('force-puppet') puppetlabs_enabled = host_param_true?('enable-puppetlabs-repo') %>
Capturing Major and Minor Versions of a Host’s Operating System
The following example shows how to capture the minor and major version of the host’s operating system, which can be used for package related decisions:
<% os_major = @host.operatingsystem.major.to_i os_minor = @host.operatingsystem.minor.to_i %> <% if ((os_minor < 2) && (os_major < 14)) -%> ... <% end -%>
Importing Snippets to a Template
The following example imports the subscription_manager_registration snippet to the template and indents it by four spaces:
<%= indent 4 do snippet 'subscription_manager_registration' end %>
Conditionally Importing a Kickstart Snippet
The following example imports the kickstart_networking_setup
snippet if the host’s subnet has the DHCP boot mode enabled:
<% subnet = @host.subnet %> <% if subnet.respond_to?(:dhcp_boot_mode?) -%> <%= snippet 'kickstart_networking_setup' %> <% end -%>
Parsing Values from Host Custom Facts
You can use the host.facts
variable to parse values from a host’s facts and custom facts.
In this example luks_stat
is a custom fact that you can parse in the same manner as dmi::system::serial_number
, which is a host fact:
'Serial': host.facts['dmi::system::serial_number'], 'Encrypted': host.facts['luks_stat'],
In this example, you can customize the Applicable Errata report template to parse for custom information about the kernel version of each host:
<%- report_row( 'Host': host.name, 'Operating System': host.operatingsystem, 'Kernel': host.facts['uname::release'], 'Environment': host.lifecycle_environment, 'Erratum': erratum.errata_id, 'Type': erratum.errata_type, 'Published': erratum.issued, 'Applicable since': erratum.created_at, 'Severity': erratum.severity, 'Packages': erratum.package_names, 'CVEs': erratum.cves, 'Reboot suggested': erratum.reboot_suggested, ) -%>