Changes between Version 14 and Version 15 of Tutorials/a0Basic/Tutorial2


Ignore:
Timestamp:
Nov 21, 2007, 7:22:30 AM (16 years ago)
Author:
thierry
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Tutorials/a0Basic/Tutorial2

    v14 v15  
    1 = Tutorial 1: Hello World Example =
     1= Basic Tutorial: Hello World Example =
    22[wiki:Tutorial Back]
    3 [[TOC(heading=Tutorial TOC, Tutorial, Tutorial/Testbed, Tutorial/HowtoWriteScripts, Tutorial/HelloWorld,   Tutorial/CollectMeasurements, Tutorial/AnalyzeResults, depth=2)]]
    4 
    5 In the "Hello World" experiment, a ''sender'' node sends a data stream to a ''receiver'' node.  The script for this experiment is shown below.
    6 
    7 {{{
    8 
    9 #
    10 # Define nodes used in experiment
     3[[TOC(heading=Tutorial TOC, Tutorial, depth=2)]]
     4
     5== 1. Developing a Script for an Experiment ==
     6
     7As explained in the previous [wiki:Tutorial/Testbed overview] page, to run an experiment on the testbed a user needs to first describes this experiment in a ''script''. This ''script'' is then passed on to a '''Node Handler''', which will use it to run and control the experiment execution.
     8
     9This script contains the experiment configuration and scenario. More precisely, it includes:
     10 * a description of the required resources (e.g. nodes on the testbed, applications to run),
     11 * their initializations and optional associations (e.g. nodeX is connected to NodeY, all nodes use channel 6 of 802.11g),
     12 * 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). 
     13
     14ORBIT experiment scripts are written using the Ruby scripting language. However, a user does '''not''' necessary 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 experiment, 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).
     15
     16[[BR]]
     17== 2. "Hello World" experiment ==
     18
     19In this basic experiment, we define two groups of node: a ''sender'' and a ''receiver'' group. Although a group of node 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.
     20
     21The script for this experiment is shown below.
     22
     23{{{
     24#
     25# A)  Define the 'sender' group, which has the unique node [1,1]
     26#     Nodes in this group will execute the application 'test:proto:sender'
    1127#
    1228defNodes('sender', [1,1]) {|node|
     29
    1330  node.prototype("test:proto:sender", {
    1431    'destinationHost' => '192.168.1.2',
     
    1734    'protocol' => 'udp'   
    1835  })
     36
    1937  node.net.w0.mode = "managed"
    2038}
    2139
     40#
     41# B)  Define the 'receiver' group, which has the unique node [1,2]
     42#     Nodes in this group will execute the application 'test:proto:receiver'
     43#
    2244defNodes('receiver', [1,2]) {|node|
     45
    2346  node.prototype("test:proto:receiver" , {
    2447    'protocol' => 'udp'
    2548  })
     49
    2650  node.net.w0.mode = "master"
    2751}
    2852
     53#
     54# C)  Configure the wireless interfaces of All the Nodes involved in
     55#     this experiment
     56#
    2957allNodes.net.w0 { |w|
    3058  w.type = 'b'
     
    3462
    3563#
    36 # Now, start the application
     64# D)  When all the nodes are turned On and the all the applications
     65#     are installed and ready, we can start to perform the experiment
    3766#
    3867whenAllInstalled() {|node|
     68
    3969  wait 30
    4070
     
    4676}}}
    4777
    48 Figure 1.  Script for "Hello World" Experiment
    49 
    50 == Understanding the Hello World ==
    51 
    52 The first part of the script creates a group called ''sender'' and assigns node1-1 to it.
    53 Next, we instruct nodehandler to assign the prototype [http://www.orbit-lab.org/wiki/Documentation/OTG/ScriptsRepository/ProtoDefSender ''test:proto:sender'']  to node1-1. A prototype is similar to a function or macro in conventional programming languages and defines in this case a re-usable configuration. The prototypes are normally defined in separate files.  In this case, the prototype contains instructions to install a traffic generator, but we will learn about this later. What is important here is that a prototype can define properties which allows us to customize it for the specific experiment. In this experiment, we can set the address of the sender, and various properties of the traffic generator itself, such as packet size, rate, and the protocol over which to send the traffic.
    54 
    55 {{{
    56 defNodes('sender', [1,1]) {|node|                   
     78[[BR]]
     79== 3. Understanding the "Hello World" script ==
     80
     81As 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 experiment on the ORBIT testbed.
     82
     83 * The first part of this script uses the ORBIT method ''defNodes'' to define a group of nodes called ''sender'', which contains a unique node ''[1,1]''. Next, we perform some specific configurations on the node(s) within the group ''sender''. These specific configurations are described in a ''block'' (e.g. curly braces) that directly follows the ''defNodes'' call. Within this ''block'', we first assign a particular application to the ''sender'' node(s). This application is a traffic generator and is accessed via a ''prototype'' which is called ''test:proto:sender'' in this example. A prototype can be viewed as a wrapper around an existing application. It defines some set of properties (i.e. "parameters"), which allows us to customize the wrapped application for the specific need of an experiment. For example in this case, through the prototype we can set the address of the sender, and various parameters of the traffic generator itself, such as packet size, rate, and the protocol over which to send the traffic. Prototypes are normally defined in separate files, and the ORBIT platform has a set of predefined prototypes for some basic applications. For example, the prototype "test:proto:sender" is a wrapper around the application "otg" (orbit traffic generator). Other tutorials (see [wiki:Tutorial main page]) describes how to write your own prototypes for your own or existing applications. The last line on this 'sender' block configures the first wireless interface ''w0'' on the node(s) in this block into ''managed'' mode.
     84
     85{{{
     86#
     87# A)  Define the 'sender' group, which has the unique node [1,1]
     88#
     89defNodes('sender', [1,1]) {|node|       
     90           
     91  # Assign the prototype "test:proto:sender" to the node(s) in this group
    5792  node.prototype("test:proto:sender", {
     93
     94    # Configure the properties for this prototype, i.e. the parameters for the wrapped application
    5895    'destinationHost' => '192.168.1.2',
    5996    'packetSize' => 1024,
     
    6198    'protocol' => 'udp'
    6299  })
     100
     101  # Configure the wireless interface "w0" of the node(s) in this group
     102  # Put the interface into "Managed" mode.
    63103  node.net.w0.mode = "managed"
    64104}
    65105}}}
    66 The last line 'node.net.w0.mode' configures the first wireless interface ''w0'' to be used in ''managed'' mode.
    67 
    68 The next block of code defines node1-2 as a receiver in similar fashion. We are using the ''receiver'' prototype here which installs a traffic sink. In addition, we are setting the receiver's first wireless interface to ''master'' mode.
    69 
    70 {{{
     106
     107 * The second part of the script is very similar to the previous one. Here we define a 'receiver' group with a unique node, this time node [1,2]. Again we define some specific configuration for the 'receiver' nodes in a block following the ''defNodes'' call. In this case, we assign a traffic sink application to the node(s) via a prototype called "test:proto:receiver", we also set the 'protocol' property of this prototype. Finally, we configure the "w0" wireless interface of the node(s) into "master" mode.
     108
     109{{{
     110#
     111# B)  Define the 'receiver' group, which has the unique node [1,2]
     112#
    71113defNodes('receiver', [1,2]) {|node|
     114
     115  # Assign the prototype "test:proto:receiver" to the node(s) in this group
    72116  node.prototype("test:proto:receiver" , {
    73117    'protocol' => 'udp'
    74118  })
     119
     120  # Configure the wireless interface "w0" of the node(s) in this group
    75121  node.net.w0.mode = "master"
    76122}
    77123}}}
    78124
    79 What follows is an example on how to configure interfaces on all nodes in one place to ensure consistency. The command ''allNodes.net.w0'' describes the first wireless interface on all nodes in the experiment. The code inside the curly braces configures various parameters of these interfaces. In this specific example we configure the interface as an 802.11b type, set the ''essid'' to a common string, and set it's IP address. We obviously do not want to set all the interfaces to the same IP address, but any string beginning with a '%' is ''personalized'' for each node by replacing characters preceeded by a '%' with a local string. In this specific example, '%y' is replaced by the 'y' coordinate of the node. For this specific experiment setup, the IP address of node1_1 will be 192.168.1.1, while node1_2 will have 192.168.1.2 assigned.
    80 
    81 {{{
     125
     126 * The third part of the script presents an example on how to configure interfaces on all nodes in one place to ensure consistency. The command ''allNodes.net.w0'' describes the first wireless interface on all nodes in the experiment. The code inside the following ''block'' (e.g. curly braces) configures various parameters of these interfaces. In this specific example, we configure the interface as an 802.11b type, set the ''essid'' to a common string, and set it's IP address. We obviously do not want to set all the interfaces to the same IP address, thus any string beginning with a '%' is ''personalized'' for each node by replacing characters prefixed by a '%' with a local string. In this specific example, '%y' is replaced by the 'y' coordinate of the node. For this specific experiment setup, the IP address of node [1,1] will be 192.168.1.1, while node [1,2] will have 192.168.1.2 assigned. This part concludes the configuration phase of the experiment.
     127
     128{{{
     129#
     130# C)  Configure the wireless interfaces of All the Nodes in this experiment
     131#
    82132allNodes.net.w0 { |w|
    83133  w.type = 'b'
     
    87137}}}
    88138
    89 This concludes the configuration steps and we will now describe the experiment itself. The experiment script basically defines a state machine, or more precisely, what sequence of commands should be executed if the experiments enters a particular state. The only state we will use in this experiment is ''whenAllInstalled'' which the experiment controller reaches when all nodes are configures and all requested applications are installed and ready to go.
    90 {{{
     139 * This final part of the script describes the operation to execute in order to perform the experiment. An ORBIT experiment script basically defines a state machine, or more precisely, what sequence of commands should be executed if the experiments enters a particular state. The only state we will use in this experiment is ''whenAllInstalled''. This state is reached when all the nodes are configures and all the requested applications are installed and ready to go. The sequence of commands to perform are given in a ''block'' following the ''whenAllInstalled'' call. The first command 'wait 30' will suspend the execution for 30 seconds to ensure that indeed everything has settled. The ''allNodes.startApplications'' will then send a command to all nodes to start the applications assigned to them (via the use of ''prototypes'') in the previous script parts. Thus in this example, this command will start a traffic generator on node [1,1] and a corresponding sink on node [1,2]. The different parameters for these applications are taken from the above definition as well. Finally, the next line 'wait 40' will suspend the control of the experiment for 40 seconds (during which the applications on the nodes '''will run''' and exchange traffic), before concluding the experiment with a call to ''Experiment.done''.
     140
     141{{{
     142#
     143# D)  When all the nodes are turned On and the all the applications
     144#     are installed and ready, we can start to perform the experiment
     145#
    91146whenAllInstalled() {|node|
     147 
     148  # Wait 30sec
    92149  wait 30
    93150
     151  # Start all the Applications on all the nodes
    94152  allNodes.startApplications
     153
     154  # Wait for 40sec
    95155  wait 40
    96156
     157  # Stop the experiment execution
    97158  Experiment.done
    98159}
    99160}}}
    100 The first command 'wait 30' will block for an additional 30 seconds to ensure that indeed everything has settled. The ''allNodes.startApplications'' will send a command to all nodes to start the applications defined in the above 'defNodes' block, or more precisly the used prototypes. In our experiment, this command will start a traffic generator in node1_2 and a corresponding sink in node1_2. The rate and packet size parameters for the traffic generator are taken from the above definition as well.
    101 
    102 The next line 'wait 40' will instruct the experiment controller to wait for 40 seconds before concluding the experiment (''Experiment.done'').
    103 
    104 == Running Hello World ==
    105 Reserve a time slot on one of the sandboxes, log into the appropriate console machine, image the nodes and run "nodehandler --tutorial".
    106 Your console output should look something like this:
    107 
    108 {{{
    109 console.grid:~/topology# nodehandler4 -d grid --tutorial
    110 DEBUG Experiment: Domain: grid
     161
     162[[BR]]
     163== 4. Running the "Hello World" experiment ==
     164
     165Before being able to run this experiment, you should:
     166
     167 * [http://www.orbit-lab.org/wiki/Registration Register] for an account (if you have not done so yet)
     168 * [https://www.orbit-lab.org/schedule/ Make a reservation] on the Scheduler for a time slot on one of the sandbox testbed
     169 * Log into the console machine corresponding to this testbed
     170 {{{
     171  # User Bob reserved a time slot on the sandbox1 testbed.
     172  # He then can access the sandbox1 console using the command:
     173 
     174  ssh bob@console.sb1.orbit-lab.org
     175 }}}
     176
     177 * Image the nodes of this testbed with a disk image such as the latest ''baseline.ndz'' image, which includes ''nodeAgent4''. Instructions on how to image the nodes on a testbed can be found [wiki:Tutorial/HowToImage here]
     178
     179Once the nodes have been imaged, you can run the "Hello World" experiment with the command:
     180
     181{{{
     182nodehandler --tutorial
     183}}}
     184Note: Normally an experiment is described in a script file, e.g. "my_experiment.rb", which is run by using the command "nodehandler my_experiment". However in this particular case, the tutorial script is already stored in a repository known by the ''nodehandler'' application. Thus the "--tutorial" option instructs the ''nodehandler'' to fetch that script and execute it.
     185
     186After running the above command, your console output should look like this:
     187
     188{{{
     189console.sb1:~# nodehandler --tutorial
     190DEBUG Experiment: Domain: sb1
    111191 INFO init: NodeHandler Version 4.2.0 (1272)
    112  INFO init: Experiment ID: grid_2007_11_19_19_15_19
    113  INFO ExecApp: Starting application 'commServer': /opt/nodehandler4-4.2.0/sbin/commServer --logfile /tmp/commServer-grid_2007_11_19_19_15_19.log -d 4 --iface eth1
     192 INFO init: Experiment ID: sb1_2007_11_19_19_15_19
    114193 INFO Experiment: load system:exp:stdlib
    115194 INFO prop.resetDelay: resetDelay = 210:Fixnum
    116195 INFO prop.resetTries: resetTries = 1:Fixnum
    117196 INFO Experiment: load test:exp:tutorial-1a
    118  INFO stdlib: Waiting for nodes (Up/Down/Total): 0/2/2 - (still down: n_1_2,n_1_1)
    119  INFO stdlib: Waiting for nodes (Up/Down/Total): 0/2/2 - (still down: n_1_2,n_1_1)
    120  INFO stdlib: Waiting for nodes (Up/Down/Total): 0/2/2 - (still down: n_1_2,n_1_1)
    121  INFO stdlib: Waiting for nodes (Up/Down/Total): 0/2/2 - (still down: n_1_2,n_1_1)
    122  INFO stdlib: Waiting for nodes (Up/Down/Total): 0/2/2 - (still down: n_1_2,n_1_1)
    123  INFO stdlib: Waiting for nodes (Up/Down/Total): 0/2/2 - (still down: n_1_2,n_1_1)
    124197 INFO stdlib: Waiting for nodes (Up/Down/Total): 0/2/2 - (still down: n_1_2,n_1_1)
    125198 INFO stdlib: Waiting for nodes (Up/Down/Total): 0/2/2 - (still down: n_1_2,n_1_1)
     
    136209 INFO Experiment: DONE!
    137210 INFO ExecApp: Application 'commServer' finished
    138  INFO run: Experiment grid_2007_11_19_19_15_19 finished after 3:41
    139 console.grid:~/topology#                                         
    140 }}}
    141  
    142 == Prototypes and application definitions used with helloworld ==
    143 
    144  * [wiki:Documentation/OTG/ScriptsRepository/OtgAppDef otg.rb]
    145  * [wiki:Documentation/OTG/ScriptsRepository/OtrAppdef otr.rb]
    146  
    147  * [wiki:Documentation/OTG/ScriptsRepository/ProtoDefSender sender.rb]
    148  * [wiki:Documentation/OTG/ScriptsRepository/ProtoDefReceiver receiver.rb]
     211 INFO run: Experiment sb1_2007_11_19_19_15_19 finished after 3:41
     212console.sb1:~#                                         
     213}}}
     214
     215'''Congratulation''' you just ran your first experiment script on the Orbit Testbed!
     216
     217You will find information on how to collect and interpret measurements and results from your experiment in the next parts of this basic tutorial, [wiki:Tutorial/CollectMeasurements here] and [wiki:Tutorial/AnalyzeResults here]
     218
     219[[BR]]
     220== 5. Beyond the Basics ==
     221
     222=== 5.1. More on the Ruby Language and the ORBIT-specific Ruby methods ===
     223
     224As 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:
     225
     226  * [wiki:Tutorial/HowtoWriteScripts/RubyResources Ruby Resources]
     227  * [wiki:Tutorial/HowtoWriteScripts/OrbitRuby ORBIT Specific Ruby Methods]
     228
     229=== 5.2. More Tutorials ===
     230
     231Once you are done with the remaining parts of this basic tutorial (i.e. [wiki:Tutorial/CollectMeasurements collecting] and [wiki:Tutorial/AnalyzeResults interpreting] experiment measurements and results), you might want to have a look at the other tutorials on the [wiki:Tutorial main page] to further learn about the other ORBIT functions that can help you develop your own complex experiments.
     232
     233=== 5.3. Definitions of the Prototypes and Application used in the "Hello World" script ===
     234
     235 * Orbit Traffic Generator (OTG) [[BR]] [wiki:Documentation/OTG/ScriptsRepository/ProtoDefSender sender.rb] is the file that contains the "test:proto:sender" prototype, which wraps around the [wiki:Documentation/OTG/ScriptsRepository/OtgAppDef otg.rb] application.
     236 * Orbit Traffic Receiver (OTR) [[BR]] [wiki:Documentation/OTG/ScriptsRepository/ProtoDefReceiver receiver.rb] is the file that contains the "test:proto:receiver" prototype, which wraps around the [wiki:Documentation/OTG/ScriptsRepository/OtrAppdef otr.rb] application.