Jump to contentJump to page navigation: previous page [access key p]/next page [access key n]
documentation.suse.com / SUSE Linux Enterprise Server Documentation / AutoYaST Guide / Managing mass installations with dynamic profiles / ERB templates
Applies to SUSE Linux Enterprise Server 15 SP3

7 ERB templates

ERB templates are for embedding Ruby code within an AutoYaST profile to modify the profile during the installation. With this approach, you can inspect the system and adjust the profile by setting values, adding or skipping sections, and so on.

To activate the ERB processing, the profile must have the extension .erb (for example, autoyast.xml.erb). Hence, it is not possible to combine rules/classes and ERB templates.

7.1 What is ERB?

ERB stands for Embedded Ruby. ERB uses the power of the Ruby programming language to generate different kind of content. With ERB, you can include some Ruby code in your profiles to adapt them at runtime, depending on the installation system.

When using ERB, the Ruby code is enclosed between <% and %> signs. Use an equals sign, =, to include command output in the resulting profile.

Example 7.1: Including a file using ERB
  <% require "open-uri" %>
  <%= URI.open("").read %>
</bootloader> <!-- this line gets replaced with the content of bootloader-common.xml -->

You can use Ruby facilities to run arbitrary commands. If you want to get the output of a command, then enclose it between backticks. If you want to know whether a command was successful or not, run the command with the system function.

Example 7.2: Running commands with Ruby
<% files = `ls` %> <!-- files contains the output of the command (for instance "file1\nfile2\nfile3") -->
<% success = system("dmidecode | grep some-model") %> <!-- success contains true or false -->

Also, you can use more advanced Ruby code structures such as conditions and loops.

Example 7.3: Using Ruby structures
<% ip_forward = File.read("/proc/sys/net/ipv4/ip_forward").strip %>
<% if ip_forward == "1" %>
  <!-- something -->
<% end %>

<% files = `ls /tmp/config/*.xml` %>
<% files.split.each do |file| %>
  <%= file.read %>
<% end %>

AutoYaST offers a small set of helper functions to retrieve information from the underlying system, like disks or network_cards. You can check the list of helpers and their values in the Section 7.2, “Template helpers” section.

7.2 Template helpers

Template helpers are sets of Ruby methods that can be used in the profiles to retrieve information about the installation system.

7.2.1 boot_efi?

boot_efi? is a boolean helper that returns whether the system is booted using EFI. In the example below, the profile configures the bootloader according to the current boot mode.

Example 7.4: Configuring the boot loader
<% if env.boot_efi? %>
<% else %>
<% end %>

7.2.2 disks

The disks helper returns a list of the detected disks. Each element of the list contains some basic information like the device name or the size.






Device kernel name (for example, sda).



Disk model



Serial number



Disk size (is a count of disk sectors)



List of disk udev names. You can use any of them to refer to the device.



Disk vendor's name

The profile in the example below installs the system on the largest disk. It sorts the list of existing disks by size and takes the last one. Then it uses the :device key as value for the device element.

Example 7.5: Using the largest disk
<partitioning t="list">
    <% disk = disks.sort_by { |d| d[:size] }.last %> <!-- find the largest disk -->
    <device><%= disk[:device] %></device> <!-- print the disk device name -->
    <initialize t="boolean">true</initialize>

7.2.3 network_cards

The network_cards helper returns a list of network cards, including their names, status information (for example, if they are connected or not).






Device name (for example, eth0 or enp3s0)



MAC address



Whether the device is active or not



Whether the device is connected or not



Disk vendor's name

The following example finds the first network card that is connected to the network and configures it to use DHCP.

Example 7.6: Configure the connected network cards
<interfaces t="list">
  <% with_link = network_cards.sort_by { |n| n[:name] }.find { |n| n[:link] } %>
  <% if with_link %>
      <device><%= with_link[:device] %></device>
  <% end %>

7.2.4 os_release

The os_release helper returns the operating system information, which is included in the /etc/os-release file.






Distribution ID (for example, sles, opensuse-tumbleweed)



Distribution name (for example, SLES or openSUSE Tumbleweed)



Distribution version (for example, 15.2)

You might use this information to decide which product to install, using pretty much the same profile for all of them (SLE or openSUSE distributions).

Example 7.7: Reusing the same profile for different distributions
<products t="list">
  <% if os_release[:id] == 'sle' %>
  <% else %>
  <% end %<

7.2.5 hardware

The hardware helper provides additional hardware information. It returns all the information from hwinfo command. You can use this helper as an escape hatch for those cases in which the information available through the described helpers is not enough. In the next example, hardware helper is used to filter USB devices. Check Section 7.3, “Running ERB helpers” to learn how to inspect all the information provided by the hardware helper.

Example 7.8: Filtering USB devices
<% usb_disks = hardware["disk"].select { |d| d["driver"] != "usb-storage" } %>

7.3 Running ERB helpers

You can use the Ruby console to run AutoYaST ERB helpers and find out what they offer. All ERB helpers are accessed through an instance of the Y2Autoinstallation::Y2ERB::TemplateEnvironment class. Start the Ruby interactive interpreter by running, as root: irb -ryast -rautoinstall/y2erb.

Example 7.9: Running helpers
irb > env = Y2Autoinstallation::Y2ERB::TemplateEnvironment.new  # the env variable gives access to the helpers

irb > env.disks
[{:vendor=>"WDC", :device=>"sda", ...},
 {:vendor=>"TOSHIBA", :device=>"sdb", ...},

irb > env.hardware.keys

irb > env.hardware["architecture"]

7.4 Rendering ERB profiles

The AutoYaST command line provides a check-profile command that can be used to generate a profile from a ERB file. This command asks AutoYaST to parse, run the ERB code, and generate the resulting profile. You can inspect the rendered profile to check that everything worked as expected. See the command help for all the options if supports: autoyast check-profile --help. In the following example check-profile asks AutoYaST to download and parse the profile, interpret the ERB code and run the pre-scripts. The result will be dumped to the result.xml file.

Example 7.10: Rendering profile
 > sudo yast2 autoyast check-profile filename= output=result.xml run-scripts=true run-erb=true
Warning: check-profile permissions

In most cases, check-profile requires root permissions, so be careful when running pre-installation scripts and ERB profiles as root. Use only profiles that you trust.

7.5 Debugging ERB profiles

For those cases in which you would like to stop the ERB evaluation and check what is happening, YaST offers integration with the byebug debugger. Install the rubygem(byebug) package and set the Y2DEBUGGER environment variable to 1.

Example 7.11: Preparing the debug environment
> sudo zypper --non-interactive in "rubygem(byebug)"
> sudo Y2DEBUGGER=1 yast2 autoyast check-profile ...

Adding breakpoints is as easy as adding <% byebug %> where you want to stop. For more information about byebug, see https://github.com/deivid-rodriguez/byebug.

Example 7.12: Adding a breakpoint
<% byebug %>
<% if system("dmidecode | grep some-model") %>
  <!-- do something -->
%<% end %>

7.6 ERB vs. rules and classes

Although both ERB and rules/classes enable generating profiles dynamically, in general ERB profiles are easier to read and understand. One important difference is that rules and classes can merge profiles, and ERB can not. See more about merging profiles at Chapter 6, Rules and classes. On the other hand, ERB brings all the power of a high level language, Ruby. Let's see an example using both. In the following example, we want to place /home directory in /dev/sdb if it exists.

Example 7.13: Rules and classes
if blkid | grep /dev/sdb > /dev/null; then
echo -n "yes"
echo -n "no"
    <dont_merge config:type="list">
Example 7.14: ERB
<% home_in_sdb = disks.map { |d| d[:device] }.include?("sdb") %>

<partitioning config:type="list">
  <% if home_in_sdb %>
    <partitions t="list">
        <format t="boolean">true</format>
        <filesystem t="symbol">xfs</filesystem>
  <% end %>