Skip to content

Recipe XML Format

jtluka edited this page Aug 21, 2013 · 30 revisions

This page needs reviewing!


This document describes the format of recipe XML files accepted by lnst-ctl. This is more of a reference guide than a manual or how-to. If you want to know how to structure your very first recipe, please refer to How to Structure LNST Recipe.

0. Index

Here is a map of the XML format. To get a description of a tag, click on its name.

<lnstrecipe>

1. Recipe Structure

LNST recipes have the following structure:

<lnstrecipe>
    <machines>
        ...
    </machines>

    <task>
    <task>
    ...
</lnstrecipe>

You need to provide information about the machines required for the test. All these information are listed under the <machines> tag. After that you can specify one or more tasks to be executed. Each task is enclosed in a <task> tag. Think of tasks as test cases.

ELEMENT: <lnstrecipe>
Root element required in every valid LNST recipe.
Attributes: Required: None
Optional: None
Children: Required: <machines>
<task>
Optional: None

2. Machines

There must be exactly one <machines> tag provided in every valid LNST recipe. The tag contains an enumeration of machine details (in the form of <machine> tags) required to perform the test.

ELEMENT: <machines>
Contains a list of machines required to perform the test.
Attributes: Required: None
Optional: None
Children: Required: <machine>
Optional: None
Example
<machines>
    <machine id="1">...</machine>
    <machine id="peanut">...</machine>
    ...
</machines>

2.2 Machine tag

Each machine tag can contains two sections, parameters within the <params> tag and enumeration of the its interfaces (<interfaces> tag). The former is optional, the latter mandatory. You can request a number of parameters for the machine to have, such as a type and version of the operating system, even some hardware details.

ELEMENT: <machine>
Specification of a machine that is required to perform the test.
Attributes: Required: [string] id: An unique identifier of the machine
Optional: None
Children: Required: <interfaces>
Optional: <params>
ELEMENT: <params>
The parameters of a machine.
Attributes: Required: None
Optional: None
Children: Required: <param>
Optional: None
ELEMENT: <param>
A single parameter of a machine.
Attributes: Required: [string] name: The name of the parameter
[string] value: The required value
Optional: None
Children: Required: None
Optional: None
Example
<machine id="peanut">
    <params>
        <param name="os" value="rhel6.2"/>
        <param name="type" value="server"/>
    </params>
    <interfaces>...</interfaces>
</machine>

2.3 Interfaces

The second (and far more complicated) part of machine specification is the network configuration. In this section of the recipe, you need to specify what interfaces you would like for the machine to have and how they should be configured. You will be able to refer to the herein configured devices from the tasks.

ELEMENT: <interfaces>
List of interfaces of a machine with their configuration
Attributes: Required: None
Optional: None
Children: Required: one of following:
<eth>
<bond>
<team>
<vlan>
<bridge>
<macvlan>
Optional: None
ELEMENT: <eth>, <bond>, <team>, <vlan>, <bridge>, <macvlan>
Test interface configuration
Attributes: Required: [string] id: unique identifier of the interface
[string] network: the network segment this network device is connected to; Note: required for <eth> only
Optional: None
Children: Required: None
Optional: <addresses>
<options> Note: applicable to all except <eth>
<params> Note: applicable to <eth> only
<slaves> Note: applicable to all except <eth>

2.3.1 Addresses

Address can be assigned to all interface types.

ELEMENT: <addresses>
A list of addresses to be assigned to this interface
Attributes: Required: None
Optional: None
Children: Required: <address>
Optional: None
ELEMENT: <address>
An address
Attributes: Required: [string] value: IP or IP6 address
Optional: None
Children: Required: None
Optional: None

2.3.2 Options

Some interface types have configurable options. Use the option child tag to set them.

ELEMENT: <options>
A list of configuration options
Attributes: Required: None
Optional: None
Children: Required: <option>
Optional: None
ELEMENT: <option>
An option
Attributes: Required: [string] name: option name
[string] value: option value; Note: Value can also be passed as tag content
Optional: None
Children: Required: None
Optional: None

2.3.3 Params

The parameters tag allows you to request specific details about the interface, such as the driver, NIC model, etc.

ELEMENT: <params>
The parameters of an interface.
Attributes: Required: None
Optional: None
Children: Required: <param>
Optional: None
ELEMENT: <param>
A single parameter of an interface.
Attributes: Required: [string] name: The name of the parameter
[string] value: The required value
Optional: None
Children: Required: None
Optional: None

2.3.4 Slaves

Interfaces that are not associated with any physical device (don't have a phys_id assigned) usually have slave interfaces assigned.

ELEMENT: <slaves>
A list of slave interfaces
Attributes: Required: None
Optional: None
Children: Required: <slave>
Optional: None
ELEMENT: <slave>
Slave interface
Attributes: Required: [string] id: slave identifier
Optional: None
Children: Required: None
Optional: None

LNST is even able to configure multiple network devices into bonds and teams. It can also perform VLAN and bridging configuration for you.

2.4 Interface types

We will have a closer look at the configuration of different interface types in the following sections.

2.4.1 Simple Ethernet Interface

When setting up a plain Ethernet interface you need to specify an id, type, and a network. The network attribute tells LNST to which network segment is this interface connected to. You also need to configure an address using the addresses tag. See the example below:

Example
<interfaces>
    <eth id="testiface" network="net1">
        <addresses>
            <address value="192.168.100.226/24"/>
        </addresses>
    </eth>
    <eth id="2" network="net1">
        <addresses>
            <address value="192.168.100.240/24"/>
        </addresses>
    </eth>
</interfaces>

2.4.2 Bonding

Slaves

The configuration of a bond is a little more tricky. Firstly, you need to have two ethernet interfaces which will be part of the bond.

<eth id="test_if1" network="net1"/>
<eth id="test_if2" network="net2"/>

After that, it is necessary to create a new interface of type bond. Then you will need to specify the slave interfaces that will be part of the bond:

<slaves>
    <slave id="test_if1"/>
    <slave id="test_if2"/>
</slaves>
Options

The bonding driver also has a lot of configurable parameters. You can specify any of them using the option tag. For the full list of available parameters, please refer to the original bonding driver documentation.

<options>
    <option name="mode" value="0"/>
    <option name="miimon" value="100"/>
</options>
Bond Example
<machine id="testmachine1">
    <interfaces>
        <eth id="test_if1" network="net1"/>
        <eth id="test_if2" network="net1"/>
        <bond id="test_bond">
            <slaves>
                <slave id="test_if1"/>
                <slave id="test_if2"/>
            </slaves>
            <options>
                <option name="mode" value="0"/>
                <option name="miimon" value="100"/>
            </options>
            <addresses>
                <address value="192.168.200.1/24"/>
            </addresses>
        </bond>
    </interfaces>
</machine>

2.4.3 vlan

Slaves

First you need to initialize the interface which will be used to configure the VLAN:

<eth id="test_if1" network="net1"/>

The interface is "enslaved" under the newly created VLAN interface using the [#element:slaves ] tag:

<slaves>
    <slave id="test_if1"/>
</slaves>
Options

The only supported option for VLANs is vlan_tci. It can be configured as follows:

<options>
    <option name="vlan_tci" value="10"/>
</options>
VLAN Example
<machine id="testmachine1">
    <interfaces>
        <eth id="1" network="net1"/>
        <vlan id="testifc1"/>
            <options>
                <option name="vlan_tci" value="10"/>
            </options>
            <slaves>
                <slave id="1"/>
            </slaves>
            <addresses>
                <address value="192.168.200.2/24"/>
            </addresses>
        </vlan>
    </interfaces>
</machine>

2.4.4 MAC-VLAN

Slave

First you need to initialize the underlying interface which will be used to configure the MAC-VLAN:

<eth id="test_if1" network="net1"/>

The interface is "enslaved" under the newly created MAC-VLAN interface using the [#element:slaves ] tag:

<slaves>
    <slave id="test_if1"/>
</slaves>
MAC-VLAN Example
<machine id="testmachine1">
    <interfaces>
        <eth id="1" network="net1"/>
        <vlan id="testifc1"/>
            <options>
                <option name="vlan_tci" value="10"/>
            </options>
            <slaves>
                <slave id="1"/>
            </slaves>
            <addresses>
                <address value="192.168.200.2/24"/>
            </addresses>
        </vlan>
    </interfaces>
</machine>

2.4.5 Team

Slaves

First you need to initialize the interfaces which will be used to configure the team:

<eth id="1" phys_id="1"/>
<eth id="2" phys_id="2"/>
<eth id="3" phys_id="3"/>

The interfaces are "enslaved" under the newly created team interface using the [#element:slaves ] tag:

<slaves>
    <slave id="1"/>
    <slave id="2"/>
    <slave id="3"/>
</slaves>
Options

You can put a JSON (JavaScript Object Notation) configuration for the team device directly in the LNST recipe:

<options>
    <option name="teamd_config">
        {
            "hwaddr": "00:11:22:33:44:55",
            "runner": {"name": "roundrobin"}
        }
    </option>
</options>
Team Example
<interfaces>
    <eth id="1" network="net1"/>
    <eth id="2" network="net1"/>
    <eth id="3" network="net1"/>
    <team id="testiface">
        <options>
            <option name="teamd_config">
                {
                    "hwaddr": "00:11:22:33:44:55",
                    "runner": {"name": "roundrobin"}
                }
            </option>
        </options>
        <slaves>
            <slave id="1"/>
            <slave id="2"/>
            <slave id="3"/>
        </slaves>
        <addresses>
             <address value="{$testip}"/>
             <address value="{$testip6}"/>
        </addresses>
    </team>
</interfaces>

2.4.6 Bridge

Slaves

First you need to initialize the interfaces which will be used to configure the bridge:

<eth id="1" network="net1"/>
<eth id="2" network="net1"/>
<eth id="3" network="net1"/>

The interfaces are "enslaved" under the newly created team interface using the [#element:slaves ] tag:

<slaves>
    <slave id="1"/>
    <slave id="2"/>
    <slave id="3"/>
</slaves>
Address

In case of the bridge the addresses are configured directly on the interfaces.

Bridge Example
<interfaces>
    <eth id="1" network="net1">
        <addresses>
             <address value="192.168.1.101"/>
        </addresses>
    </eth>
    <eth id="2" network="net2">
        <addresses>
             <address value="192.168.1.102"/>
        </addresses>
    </eth>
    <bridge id="lnstbr">
        <slaves>
            <slave id="1"/>
            <slave id="2"/>
        </slaves>
    </bridge>
</interfaces>

3. Task

Tasks can be thought of as test cases. There should be one task for one case. There may be one or more tasks in each recipe.

ELEMENT: <task>
A sequence of commands forming a single test case
Attributes: Required: None
Optional: None
Children: Required: None
Optional: one of following: <run>
<ctl_wait>
<config>
<wait>
<intr>
<kill>
Task Example
<task>
    <command machine_id="1" timeout="30" type="exec" value="sleep 5" />
    <command machine_id="1" timeout="30" type="test" value="IcmpPing">
        <options>
            <option name="addr" value="{ip(2,1)}"/>
            <option name="count" value="40"/>
            <option name="interval" value="0.2"/>
            <option name="limit_rate" value="95"/>
        </options>
    </command>
    <command machine_id="1" timeout="30" type="test" value="IcmpPing" bg_id="1">
        <options>
            <option name="addr" value="{ip(2,1)}"/>
            <option name="count" value="40"/>
            <option name="interval" value="0.2"/>
            <option name="limit_rate" value="95"/>
        </options>
    </command>
    <command type="ctl_wait" value="5"/>
    <command machine_id="1" timeout="30" type="intr" value="1"/>
</task>

4. Commands

There are several basic command types. Specifics of each one of them are described further bellow.

ELEMENT: <command>
Test interface configuration
Attributes: Required: * [_string_] **machine_id** machine to run this command on || ||[_enum_] **type** ||command type BR **Values**: _exec_, _ctl_wait_, _intr_, _kill_, _system_config_, _test_, _wait_ || || **Optional:**||[_string_] **bg_id** ||execute command in background with a specific **bg_id** (it will be used later to interrupt or kill it) || || ||[_int_] **timeout** ||failsafe timeout to terminate command execution in case it hangs || || ||[_string_] **option** ||some command types may accept an option BR **Valid for:** _system_config_ || || ||[_string_] **value** ||some command types can accept a value BR **Valid for:** _exec_, _ctl_wait_, _intr_, _kill_, _system_config_, _test_, _wait_ || || ||[_string_] **option** ||some command types may accept an option BR **Valid for:** _system_config_ ||
Children: Required: None
Optional: <options>
ELEMENT: <options>
Set of command options
Attributes: Required: None
Optional: None
Children: Required: None
Optional: <options>
ELEMENT: <option>
Option assignment
Attributes: Required: [string] name option name (this is test-specific)
|| ||[_string_] value ||option value BR Note: If the value is longer, you can omit this attribute and put it in the contents of the tag. ||
Optional: None
Children: Required: None
Optional: None
Command Example
<command machine_id="1" timeout="30" type="exec" value="sleep 5" />

4.1 Background Execution

Commands execute in sequential order from the controller's perspective, unless you specify any of them to run in the background. To do so, you need to add a bg_id attribute to the command you want to run in the background. After doing so, you need to match the background command with one of the termination commands -- a kill, an interrupt, or a wait.

4.1.1 kill

Using kill to terminate the command will end its life with SIGKILL. In the following example, the controller will execute a ping test on machine 1 in the background. It will wait for 5 seconds and then kill the ping_cmd.

<command machine_id="1" type="test" value="IcmpPing" bg_id="ping_cmd">
    <options>
        <option name="addr" value="{ip(2,1)}"/>
        <option name="count" value="40"/>
    </options>
</command>
<command type="ctl_wait" value="5"/>
<command machine_id="1" type="kill" value="ping_cmd"/>

4.1.2 intr

Interrupt is very similar to kill. But it will send SIGINT instead.

<command machine_id="1" type="intr" value="ping_cmd"/>

4.1.3 wait

Wait will not signal the background process, but instead it will wait for it to terminate.

<command machine_id="1" type="wait" value="ping_cmd"/>

4.2 ctl_wait

This command is exceptional in the sense that it is not executed on any of the slaves. Instead it is run on the controller machine itself. Therefore it does not require a machine_id. This command can be used to make the controller wait for some time while the slaves are executing commands in the background.

<!-- Controller will wait for 5 seconds -->
<command type="ctl_wait" value="5"/>

4.3 Exec

Type exec allows you to actually execute shell commands on slave machines directly from the recipe. Needless to say, this type of command is intended to be used sporadically for short commands (such as a bash script or third party tool execution). Please do not write programs or scripts using this type of command. Also, if you need to configure a system property using /proc or /sys, please use [#system_config system_config] instead. It will take care of the clean-up at the end of the recipe. It is a good idea to set a timeout, because the command could hang.

<command machine_id="1" type="exec" timeout="30" value="tcpdump -i {devname(2, 1)}"/>

If you have any third-party tools set up with LNST, you can use the from attribute to specify which one LNST should use.

<command machine_id="1" type="exec" timeout="30" from="multicast" value="./igmp_query -a 192.168.1.101"/>

4.4 System Config

[=#system_config] System config is the native way for making changes in system configuration through /proc/ or /sys/ interface. There are two versions of the command. One-line or multi-line command that will allow you to set more options at once. Both versions are demonstrated in the following example:

<command machine_id="1" type="system_config" option="/proc/sys/net/ipv4/igmp_max_memberships" value="5" persistent="true"/>

<command machine_id="1" type="system_config">
    <options>
        <option name="/proc/sys/net/ipv4/igmp_max_memberships" value="5"/>
        <option name="/proc/sys/net/ipv4/conf/{devname(2,1)}/force_igmp_version" value="2"/>
    </options>
</command>

The persistent attribute to the first tag denotes, that that option should not be cleaned up at the end of the task. Use this if you need to set the options persistently through multiple tasks or in case the option cannot be reverted back easily (some files in /proc/ return different values than they expect, so LNST will fail to reset them to the previous state. You will need to revert the value back to the original by yourself.

4.5 Test

This class is used for executing test modules of LNST. Some modules, such as Tests/TestIcmpPing, Tests/TestIperf, or Tests/TestMulticast are direclty a part of LNST distribution, but you can add more of your custom or any other third-party modules as well. Each module can accept a different set of options through the [#element:cmd_options ] tag. Please refer to the documentation of the respective module for more information. It is also a good idea to provide a timeout, because there could be a bug in the module. See the example of IcmpPing below, other test modules are documented Tests:

<command machine_id="1" type="test" value="IcmpPing" timeout="30">
    <options>
        <option name="addr" value="{ip(2,1)}"/>
        <option name="count" value="40"/>
        <option name="interval" value="0.2"/>
        <option name="limit_rate" value="95"/>
    </options>
</command>

5. Templates

On top of the standard XML syntax, LNST Recipe format is extended with support of, so called, templates. Templates are always enclosed within a pair of curly braces {}. Templates can be used ONLY within an attribute value or within a tag's text content. Templates therefore will not work when used as a name of a tag or attribute!

There are two types of templates that will be discussed in the sections bellow: aliases and template functions.

5.1 Aliases

Aliases can be thought of as macros or variables (although they cannot be changed). You can define an alias absolutely anywhere within the document structure (as long as it does not invalidate the XML) by using the [#element:define ] tag.

<define>
    <alias name="multicast_group" value="239.1.2.3"/>
    <alias name="port" value="1337"/>
    <alias name="test_duration" value="10"/>
    <alias name="send_delay" value="0.1"/>
    <alias name="nonexistent_ip" value="127.0.0.200"/>
</define>

After you define your aliases, you will be able to reference them using the following notation: {$alias_name}. See the example bellow:

<command bg_id="1" machine_id="1" timeout="30" type="test" value="Multicast">
    <options>
        <option name="setup" value="send_simple"/>
        <option name="address" value="{$multicast_group}"/>
        <option name="port" value="{$port}"/>
        <option name="duration" value="{$test_duration}"/>
        <option name="delay" value="{$send_delay}"/>
    </options>
</command>

Alias definition's area of effect is within the tag it was defined in and in all subsequent child tags. It will be discarded as soon as the parent tag is closed.

5.2 Template Functions

Template functions are conceptually quite similar to aliases, but instead of an assigned value, they represent an action that will be executed when the recipe is parsed. They can be used the same way as aliases - inside of curly braces. Currently, there are three template functions available in LNST:

[=#ip]

5.2.1 ip(machine_id, interface_id [, address_id])

Returns an IP address for a specific machine and interface. Third argument is optional and can be used when there are multiple IP addresses associated with a single interface.

[=#hwaddr]

5.2.3 hwaddr(machine_id, interface_id`)

Returns hardware address of specified interface.

[=#devname]

5.2.2 devname(machine_id, interface_id)

Returns the device name of a specified interface.

All three above mentioned functions can be used for retrieving information from machine configs, therefore calling them is only valid within a task. See the following example on how this template can be used:

{{{#!div style="background: #ffffff; border: 1px ridge; border-color: #d7d7d7; margin: 23px"

<pre>
&lt;command type="system_config" option="/proc/sys/net/ipv4/conf/<span style="background-color:#ffc0cb">{devname(1,1)}</span>/forwarding" value="1" machine_id="1" /&gt;
&lt;command type="test" value="Multicast" machine_id="1" timeout="30"&gt;
    &lt;options&gt;
        &lt;option name="setup" value="max_groups" /&gt;
        &lt;option name="interface" value="<span style="background-color:#ffc0cb">{ip(1,1)}</span>" /&gt;
        &lt;option name="condition" value="max_groups &gt; 0" /&gt;
    &lt;/options&gt;
&lt;/command&gt;
</pre>

}}}

Aliases can be passed to functions as parameters, but the preprocessor does not support nesting (e.g. function cannot have another function passed as an argument).

6. Breaking Recipes into Multiple Files

LNST also offers a possibility of splitting the recipe into several files. It's very helpful if you want to re-use the code in different recipes. This can be achieved by supplying source argument to an arbitrary tag. The contents of that tag then will be loaded from the file specified in the attribute's value. For instance, the following machine configuration will be loaded from file peanut.xml:

{{{#!div style="background: #ffffff; border: 1px ridge; border-color: #d7d7d7; margin: 23px"

<pre>
&lt;machine <span style="background-color:#90ee90">source="machine_configs/peanut.xml"</span> /&gt;
</pre>

}}}

Example (peanut.xml): {{{#!div style="background: #ffffff; border: 1px ridge; border-color: #d7d7d7; margin: 23px"

<pre>
&lt;machine id="1"&gt;
    &lt;params&gt;
        &lt;param name="os" value="rhel6.2" /&gt;
    &lt;/params&gt;
    &lt;interfaces <span style="background-color:#add8e6">source="example_recipes/interfaces1.xml"</span> /&gt;
&lt;/machine&gt;
</pre>

}}}

Note that parts of the included machine config are again external.