[wiki:Tutorials Back] [[TOC(heading=Tutorial TOC, Tutorials, Tutorials/HelloWorld, depth=2)]] = Basic Tutorial: Hello World Example = == 1. Developing a Script for an Experiment == This tutorial presents a simple example, which shows you all the basic steps to quickly develop, run, and access the result of an experiment with OMF. Subsequent tutorials will build on this one to show you how to use other OMF features. If you are a new OMF users, you may want to read the short [http://mytestbed.net/projects/omf/wiki/An_Introduction_to_OMF OMF System Overview] and/or [http://mytestbed.net/projects/omf/wiki/UsageOverview the Experiment Life-cycle Overview]. To run an experiment on the ORBIT testbed, in addtion to all the steps from [wiki:Documentation/GettingStarted getting started], a user needs to first describe the experiment in a ''script''. This ''script/experiment description'' is then passed on to a '''Experiment Controller''', which will use it to run and control the experiment execution. This process is illustrated in figure 1. This script contains the experiment configuration and scenario. More precisely, it includes: * a description of the required resources (e.g. nodes on the testbed, applications to run), * their initializations and optional associations (e.g. nodeX is connected to NodeY, all nodes use channel 6 of 802.11g), * a description of their operation throughout the experiment duration (e.g. applicationX starts at T0 and run for 60sec, nodeY switch wireless configuration after 100sec). ORBIT experiment scripts are written using the Ruby scripting language. However, a user does '''not''' necessarily need to be familiar with Ruby to be able to write and run simple experiments. The only prerequisite skills are some prior basic knowledge and practice of any other scripting and/or programming languages (e.g. python, perl, c, java,...). Of course, to be able to develop more complex experiments a user will have to learn basics of Ruby and read about ORBIT-specific Ruby methods at some stage (more on these two issues at the end of this tutorial). [[Image(OMF-User-View.png)]] [[BR]]Figure 1. Execution of an Experiment from a User's point-of-view == 2. "Hello World" experiment == In this basic experiment, we define two groups of nodes: a ''sender'' group and a ''receiver'' group. Although a group of nodes can contain several nodes, in this simple case each group contains only one node. We also associate a traffic generator application to the ''sender'' group, and a traffic sink application to the ''receiver'' group. We then define the configuration of the wireless interfaces on the nodes within these groups. Finally, we describe the successive actions to execute in order to perform the experiment. The script for this experiment is shown below. {{{ # # Tutorial experiment # defProperty('duration', 60, "Duration of the experiment") baseTopo = Topology['system:topo:imaged'] st = defTopology("sender") do |t| t.addNode(baseTopo.getNodeByIndex(0)) end rt = defTopology("receiver") do |t| t.addNode(baseTopo.getNodeByIndex(1)) end defGroup('Sender', "sender") do |node| node.addApplication("test:app:otg2") do |app| app.setProperty('udp:local_host', '192.168.0.2') app.setProperty('udp:dst_host', '192.168.0.3') app.setProperty('udp:dst_port', 3000) app.measure('udp_out', :samples => 1) end node.net.w1.mode = "adhoc" node.net.w1.type = 'g' node.net.w1.channel = "6" node.net.w1.essid = "helloworld" node.net.w1.ip = "192.168.0.2" end defGroup('Receiver', "receiver") do |node| node.addApplication("test:app:otr2") do |app| app.setProperty('udp:local_host', '192.168.0.3') app.setProperty('udp:local_port', 3000) app.measure('udp_in', :samples => 1) end node.net.w1.mode = "adhoc" node.net.w1.type = 'g' node.net.w1.channel = "6" node.net.w1.essid = "helloworld" node.net.w1.ip = "192.168.0.3" end onEvent(:ALL_UP_AND_INSTALLED) do |event| info "This is my first OMF experiment" wait 15 allGroups.startApplications info "All my Applications are started now..." wait property.duration allGroups.stopApplications info "All my Applications are stopped now." Experiment.done end }}} == 3. Understanding the "Hello World" script == As you noticed the "Hello World" script is almost ''human-readable'', and is quite understandable to any computer-literate reader. As already mentioned above, deep Ruby knowledge is '''not''' a prerequisite to running experiments on the ORBIT testbed. {{{ defProperty('duration', 60, "Duration of the experiment") baseTopo = Topology['system:topo:imaged'] st = defTopology("sender") do |t| t.addNode(baseTopo.getNodeByIndex(0)) end rt = defTopology("receiver") do |t| t.addNode(baseTopo.getNodeByIndex(1)) end }}} This portion of the script establishes a few parameters to control the experiment behavior. In particular the ''defProperty'' function call establishes a '''duration''' property for the experiment. The baseTopo variable is set to a Topology object which has collected names of nodes from the 'system:topo:imaged' set, which was established during your last imaging (omf load) operation. Using the defTopology function we define two topolgies names "sender" and "receiver". The baseTopo object's getNodeByIndex will return a node name from the 'system:topo:imaged' set. {{{ defGroup('Sender', "sender") do |node| node.addApplication("test:app:otg2") do |app| app.setProperty('udp:local_host', '192.168.0.2') app.setProperty('udp:dst_host', '192.168.0.3') app.setProperty('udp:dst_port', 3000) app.measure('udp_out', :samples => 1) end node.net.w1.mode = "adhoc" node.net.w1.type = 'g' node.net.w1.channel = "6" node.net.w1.essid = "helloworld" node.net.w1.ip = "192.168.0.2" end defGroup('Receiver', "receiver") do |node| node.addApplication("test:app:otr2") do |app| app.setProperty('udp:local_host', '192.168.0.3') app.setProperty('udp:local_port', 3000) app.measure('udp_in', :samples => 1) end node.net.w1.mode = "adhoc" node.net.w1.type = 'g' node.net.w1.channel = "6" node.net.w1.essid = "helloworld" node.net.w1.ip = "192.168.0.3" end }}} Using the ''defGroup'' function we define "Sender" and "Receiver" groups. We associate two existing applications to each group, test:app:otg2 to the "Sender" group and test:app:otr2 to the "Receiver" group. These associations were made with the node.addApplication method. These applications would be installed and run on each node of this group. In this tutorial however, these applications are already installed on the baseline disk image, which you previously loaded on the node. These applications are a simple traffic generator and receiver respectively. By default these applications generate fixed-sized UDP packets at a constant bitrate. We set a bunch of application parameters via the app.setProperty method for each application. We also set some properties of the node using the node.net.w1.* attributes within each group. These attributes will be shared by all nodes in the group (in this case just one per group). {{{ onEvent(:ALL_UP_AND_INSTALLED) do |event| info "This is my first OMF experiment" wait 15 allGroups.startApplications info "All my Applications are started now..." wait property.duration allGroups.stopApplications info "All my Applications are stopped now." Experiment.done end }}} Finally the last block sets up the onEvent(:ALL_UP_AND_INSTALLED) trigger. When the == 4. Running the "Hello World" experiment == Before being able to run this experiment, you should: * Make sure you have followed the getting started procedure [wiki:Documentation/GettingStarted getting started] * Once you have proper reservation, login to the console. * Install a disk image which includes ''Ex'' on the nodes of this testbed. For example, you can use the latest ''baseline.ndz'' disk image. This disk image installation is done using the ''omf load'' command above. Detailed instructions on how to perform such disk image installation on the nodes on a testbed can be found [wiki:Tutorials/HowToImage here]. {{{ ssugrim@console.grid:/usr/bin$ omf help exec OMF Experiment Controller 5.4 (git c005675) Execute an experiment script Usage: exec [OPTIONS] ExperimentName [-- EXP_OPTIONS] ExperimentName is the filename of the experiment script [EXP_OPTIONS] are any options defined in the experiment script [OPTIONS] are any of the following: -a, --allow-missing Continue experiment even if some nodes did not check in -c, --config NAME Configuration section from the config file ('default' if omitted) -C, --configfile FILE File containing local configuration parameters -d, --debug Operate in debug mode -i, --interactive Run the experiment controller in interactive mode -l, --libraries LIST Comma separated list of libraries to load (defaults to [system:exp:stdlib,system:exp:eventlib,system:exp:winlib]) --log FILE File containing logging configuration information -m, --message MESSAGE Message to add to experiment trace -n, --just-print Print the commands that would be executed, but do not execute them -N, --no-am Don't use the Aggregate Manager (AM) -p, --print URI Print the contents of the experiment script -o, --output-result FILE File to write final state information to -e, --experiment-id EXPID Set the ID for this experiment, instead of the default standard ID -O, --output-app Display STDOUT & STDERR output from the executed applications -r, --reset If set, then reset (reboot) the nodes before the experiment -s, --shutdown If set, then shut down resources at the end of an experiment -S, --slice NAME Name of the Slice where this EC should operate -t, --tags TAGS Comma separated list of tags to add to experiment trace --oml-uri URI The URI to the OML server for this experiment -x, --extra-libs LIST Comma separated list of libraries to load in addition to [system:exp:stdlib,system:exp:eventlib,system:exp:winlib] --slave-mode EXPID Run in slave mode in disconnected experiment, EXPID is the exp. ID --slave-mode-resource NAME When in slave mode, NAME is the HRN of the resource for this EC -h, --help Show this message -v, --version Show the version }}} Once the nodes have been imaged, you can run the "Hello World" experiment with the ''omf exec'' command as follows: {{{ omf exec test:exp:tutorial:hello-world-wireless.rb }}} Normally an experiment is described in a script file, e.g. "my_experiment.rb", which is run by using the command "omf exec my_experiment". However in this particular case, the tutorial script is already stored in a repository known by the ''omf exec'' application. Thus the "test:exp:tutorial:hello-world-wireless.rb" option instructs the ''omf exec'' application to fetch that script and execute it. After running the above command, your console output should look like this: {{{ Test results go here: }}} '''Congratulations''' you just ran your first experiment script on the Orbit Testbed! You will find information on how to collect and interpret measurements and results from your experiment in the next parts of this basic tutorial, [wiki:Tutorials/CollectMeasurements here] and [wiki:Tutorials/AnalyzeResults here] [[BR]] [[BR]] == 5. Beyond the Basics == === 5.1. More on the Ruby Language and the ORBIT-specific Ruby methods === As mentioned previously, ORBIT experiment scripts are written in Ruby, an easily understood, extensible, dynamic, object-oriented scripting language. Ruby has been extended into the testbed user's domain with a number of methods. Besides its extensibility and object-orientation, Ruby is concise and consistent. An ORBIT script therefore is written in Ruby primarily using ORBIT-specific methods. Users are encouraged to take look at following resources: