[[TOC(Tutorials/a0Basic*)]] == Basic Tutorial: Hello World Example == 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. === Experiment Script === 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('res1', 'omf.nicta.node1', "ID of sender node") defProperty('res2', 'omf.nicta.node2', "ID of receiver node") defProperty('duration', 60, "Duration of the experiment") 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 }}} === 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. * 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. Similarly parameters are also defined for the sender and receiver nodes. {{{ defProperty('res1', 'omf.nicta.node1', "ID of sender node") defProperty('res2', 'omf.nicta.node2', "ID of receiver node") defProperty('duration', 60, "Duration of the experiment") }}} * 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). {{{ 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 }}} * Finally the last block sets up the onEvent(:ALL_UP_AND_INSTALLED) trigger. When the experimenter controller receives the :ALL_UP_AND_INSTALLED event, it will execute the steps in this block. After a global waiting time (to synchronize), the allGroups.startApplications function call will start the applications on each node. The one ''duration'' has passed the experiment will stop. {{{ 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 }}} === Running the 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 -- --res1 node1-1 --res2 node1-2 }}} 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: {{{ INFO NodeHandler: OMF Experiment Controller 5.4 (git 3fb37b9) INFO NodeHandler: Reading configuration file /etc/omf-expctl-5.4/services.yaml INFO NodeHandler: Add domain http - http://internal1.orbit-lab.org:5054/ INFO NodeHandler: Add domain http - http://repository1.orbit-lab.org:5054/ INFO NodeHandler: Slice ID: default_slice (default) INFO NodeHandler: Experiment ID: default_slice-2014-10-02t16.04.34.902-04.00 INFO NodeHandler: Message authentication is disabled INFO Experiment: load system:exp:stdlib INFO property.resetDelay: resetDelay = 230 (Fixnum) INFO property.resetTries: resetTries = 1 (Fixnum) INFO Experiment: load system:exp:eventlib INFO Experiment: load system:exp:winlib INFO Experiment: load test:exp:tutorial:hello-world-wireless.rb INFO property.res1: res1 = "node1-1" (String) INFO property.res2: res2 = "node1-2" (String) INFO property.duration: duration = 60 (Fixnum) INFO ALL_UP_AND_INSTALLED: Event triggered. Starting the associated tasks. INFO exp: This is my first OMF experiment INFO exp: Request from Experiment Script: Wait for 10s.... INFO node1-1.sb8.orbit-lab.org: Device 'net/w0' reported Not-Associated INFO node1-2.sb8.orbit-lab.org: Device 'net/w0' reported Not-Associated INFO exp: All my Applications are started now... INFO exp: Request from Experiment Script: Wait for 60s.... INFO node1-1.sb8.orbit-lab.org: Device 'net/w0' reported 12:4C:BC:B3:9E:97 INFO node1-2.sb8.orbit-lab.org: Device 'net/w0' reported 12:4C:BC:B3:9E:97 INFO exp: All my Applications are stopped now. INFO EXPERIMENT_DONE: Event triggered. Starting the associated tasks. INFO NodeHandler: INFO NodeHandler: Shutting down experiment, please wait... INFO NodeHandler: INFO run: Experiment default_slice-2014-10-02t16.04.34.902-04.00 finished after 1:20 }}} '''Congratulations''' you just ran your first experiment script on the Orbit Testbed! === Beyond the Basics === 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.