ERB テンプレートとは、プロファイル内に Ruby 言語のコードを埋め込むことのできる機能で、インストール時にプロファイルを修正する機能を提供します。この仕組みを利用することで、システムの状態を検知してプロファイル内の設定値を調整したり、セクションの追加や削除などを行ったりすることができます。
ERB 機能を有効化するには、プロファイルのファイル名に .erb という拡張子を追加します (例: autoyast.xml.erb) 。このような仕組みが存在することから、ルールやクラスと ERB テンプレートを同時に使用することはできません。
ERB とは Embedded Ruby の略で、 Ruby プログラミング言語の力を借りて様々なコンテンツ生成を行うための仕組みです。 ERB を利用してプロファイル内に Ruby コードを含めることで、インストール先のシステムに依存した様々なプロファイル調整を行うことができるようになります。
ERB を使用する場合、 Ruby 言語のコードは <% 記号から %> 記号までの間に記述します。また、コマンドの出力をそのままプロファイルに入れ込みたい場合は、イコール記号 ( = ) で設定します。
<bootloader>
<% require "open-uri" %>
<%= URI.open("http://192.168.1.1/profiles/bootloader-common.xml").read %>
</bootloader> <!-- this line gets replaced with the content of bootloader-common.xml -->Ruby の仕組みを利用することで、任意のコマンドを実行することもできます。たとえばコマンドの出力結果を取得したい場合は、コマンドの前後をバッククオートで括ります。また、コマンドの実行が成功したかどうかを調べたい場合は、 system 関数を使用してください。
<% files = `ls` %> <!-- files にはコマンドの実行結果が入ります (例: "file1
file2
file3") -->
<% success = system("dmidecode | grep some-model") %> <!-- success には true もしくは false のいずれかが入ります -->このほか条件句やループなど、高度な Ruby 言語構造を含めることもできます。
<% ip_forward = File.read("/proc/sys/net/ipv4/ip_forward").strip %>
<% if ip_forward == "1" %>
<!-- 何らかの処理 -->
<% end %>
<% files = `ls /tmp/config/*.xml` %>
<% files.split.each do |file| %>
<%= file.read %>
<% end %>AutoYaST では ヘルパー関数 と呼ばれる仕組みも提供しています。これは disks (ディスク) や network_cards (ネットワークカード) など、インストール先のシステムに関する様々な情報を取得することができる仕組みです。ヘルパーの一覧と値の意味について、詳しくは 7.2項 「テンプレートヘルパー」 をお読みください。
テンプレートヘルパーは Ruby メソッド集であり、プロファイル内で使用することで様々なインストール先システムの情報を収集することができます。
boot_efi? #Edit sourceboot_efi? はブール値のヘルパーで、システムが EFI で起動されているかどうかを表します。下記の例では、現在の起動モードに合わせてブートローダを設定しています。
<% if env.boot_efi? %> <loader_type>grub2-efi</loader_type> <% else %> <loader_type>grub2</loader_type> <% end %>
disks #Edit sourcedisks ヘルパーは、検出されたディスクの一覧を返却するヘルパー関数です。一覧の各要素には、デバイス名やサイズなどの基本的な情報が含まれます。
|
キー |
型 |
値 |
|---|---|---|
|
|
String |
デバイスのカーネル名 (例: |
|
|
String |
ディスクの型番 |
|
|
String |
シリアル番号 |
|
|
Integer |
ディスクサイズ (セクタ数) |
|
|
Array<String> |
ディスクの udev 名の一覧 (プロファイル内でデバイスを指定する際、これらのいずれかを使用することができます) |
|
|
String |
製造元の名前 |
下記のプロファイル例は、最も容量の大きいディスクに対してインストールを行う場合の例を示しています。検出されたディスクの一覧をサイズで並び替え、末尾のデバイスを選択します。あとは device 要素に対して :device キーで取得できた値を代入して使用します。
<partitioning t="list">
<drive>
<% 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>
<use>all</use>
</drive>
</partitioning>network_cards #Edit sourcenetwork_cards ヘルパーはネットワークカードの一覧を返す関数です。ここにはネットワークカードの名前のほか、状態に関する情報 (接続されているかどうかなど) も含まれています。
|
キー |
型 |
値 |
|---|---|---|
|
|
String |
デバイス名 (例: |
|
|
String |
MAC アドレス |
|
|
Boolean |
デバイスが有効化されているかどうか |
|
|
Boolean |
デバイスが接続されているかどうか |
|
|
String |
製造元の名前 |
下記の例では、ネットワークに接続されている最初のネットワークカードを検出し、そのネットワークカードで DHCP を使用するように設定します。
<interfaces t="list">
<% with_link = network_cards.sort_by { |n| n[:name] }.find { |n| n[:link] } %>
<% if with_link %>
<interface>
<device><%= with_link[:device] %></device>
<startmode>auto</startmode>
<bootproto>dhcp</bootproto>
</interface>
<% end %>
</interfaces>os_release #Edit sourceos_release ヘルパーは、オペレーティングシステムに関する情報を返す関数です。これは /etc/os-release ファイルから情報を読み込みます。
|
キー |
型 |
値 |
|---|---|---|
|
|
String |
ディストリビューション ID ( 例: |
|
|
String |
ディストリビューション名 ( 例: |
|
|
String |
ディストリビューションのバージョン ( 例: |
この情報を使用することで、インストールすべき製品を判断することができます。たとえば SLE と openSUSE で異なる設定を適用することができるようになります。
<products t="list"> <% if os_release[:id] == 'sle' %> <product>SLES</product> <% else %> <product>openSUSE</product> <% end %> </products>
hardware #Edit sourcehardware ヘルパーは追加のハードウエア情報を提供する仕組みです。ここには hwinfo コマンドからの全ての情報が含まれていて、その他のヘルパーでは不十分な場合の回避策として使用することができます。たとえば下記の例では、 hardware ヘルパーを利用して USB デバイスのフィルタリングを行っています。 hardware ヘルパーで提供される情報についての詳細は、 7.3項 「ERB ヘルパーの実行」 をお読みください。
<% usb_disks = hardware["disk"].select { |d| d["driver"] != "usb-storage" } %>AutoYaST の ERB ヘルパーを実行するにあたって Ruby コンソールを使用して結果を確認することができます。 ERB ヘルパーは Y2Autoinstallation::Y2ERB::TemplateEnvironment クラスのインスタンスを介してアクセスできます。下記のようにして root で Ruby インタプリタを起動して確認してください: irb -ryast -rautoinstall/y2erb
irb > env = Y2Autoinstallation::Y2ERB::TemplateEnvironment.new # env 変数にはヘルパーのインスタンスが代入されます
irb > env.disks
=>
[{:vendor=>"WDC", :device=>"sda", ...},
{:vendor=>"TOSHIBA", :device=>"sdb", ...},
...]
irb > env.hardware.keys
=>
["architecture",
"bios",
"bios_video",
...]
irb > env.hardware["architecture"]
=>
"x86_64"AutoYaST のコマンドラインでは check-profile コマンドが提供されています。これは ERB ファイルからプロファイルを生成するための仕組みで、このコマンドは AutoYaST に対して ERB コードの処理と実行を依頼して、プロファイルの生成を行います。これを利用することで、期待通りにプロファイルが生成されるかどうかを確認することができます。サポートされている全てのオプションを表示するには、 autoyast check-profile --help のように入力して実行してください。たとえば下記の例では、 AutoYaST に対してプロファイルのダウンロードと解釈を依頼して、 ERB コードの実行と事前スクリプトの実行までを行っています。実行結果は result.xml ファイルに出力されます。
>sudoyast2 autoyast check-profile filename=http://192.168.1.100/autoinst.erb output=result.xml run-scripts=true run-erb=true
check-profile の許可についてほとんどの場合、 check-profile には root のアクセス権限が必要となります。そのため、インストール前スクリプトや ERB プロファイルを root で動作させることになることに注意してください。信頼できるプロファイルのみを指定してください。
ERB の処理や動作を 1 つずつ確認していきたい場合は、 YaST の提供する byebug デバッガをお使いください。具体的には rubygem(byebug) パッケージをインストールしたあと、 Y2DEBUGGER 環境変数を 1 に設定します。
>sudozypper --non-interactive in "rubygem(byebug)">sudoY2DEBUGGER=1 yast2 autoyast check-profile ...
ブレークポイントを追加したい場合は、その箇所に <% byebug %> を追加するだけです。 byebug に関する詳細は、 https://github.com/deivid-rodriguez/byebug (英語) をお読みください。
<% byebug %>
<% if system("dmidecode | grep some-model") %>
<!-- 何らかの処理 -->
%<% end %>ERB とルール/クラスのどちらもプロファイルを動的に生成する仕組みですが、一般的には ERB のほうが読みやすく理解しやすい仕組みです。また、大きく異なる点として、ルールとクラスがプロファイルの合成に対応しているのに対して、 ERB は対応していないことがあげられます。プロファイルの合成に関する詳細は、 第6章 「ルールとクラス」 をお読みください。もう一方の ERB では、 Ruby という高度な言語の威力を存分に発揮することができます。たとえば下記の 2 つの例では、 /dev/sdb が存在した場合、 /home をそのデバイス内に作成するよう指示しています。
<rule>
<custom1>
<script>
if blkid | grep /dev/sdb > /dev/null; then
echo -n "yes"
else
echo -n "no"
fi;
</script>
<match>yes</match>
<match_type>exact</match_type>
</custom1>
<result>
<profile>classes/sdb_home.xml</profile>
<dont_merge config:type="list">
<element>partition</element>
</dont_merge>
</result>
</rule><% home_in_sdb = disks.map { |d| d[:device] }.include?("sdb") %>
<partitioning config:type="list">
<drive>
...
</drive>
<% if home_in_sdb %>
<drive>
<device>sdb</device>
<disklabel>none</disklabel>
<partitions t="list">
<partition>
<format t="boolean">true</format>
<filesystem t="symbol">xfs</filesystem>
<mount>/home</mount>
</partition>
</partitions>
</drive>
<% end %>
</partitioning>