Skip to content
This repository has been archived by the owner on Sep 21, 2022. It is now read-only.

Client Side Tutorial

Tobias Mende edited this page Jan 10, 2014 · 7 revisions

Preliminaries

  1. Read the OEDL introcution on mytestbed.net.
  2. Install the OMF experiment controller gem via console: gem install omf_ec --no-ri --no-rdoc
  3. Configure the experiment controller for your needs:
  • initialize the configuration: omf_ec initconfig
  • customize the config file: ~/.config/omf_ec.yml

Note: Read the OMF installation tutorial for further information.

Note 2: There are many different message types you'll receive on the client side. A detailed overview is given in the Message Documentation.

Initializing the Experiment

In this section you'll learn how to write a simple OMF experiment description using the wise_omf gem.

  1. Install the wise_omf gem: gem install wise_omf

  2. Create a configuration file containing information about your reservation on the testbed (reservation.yml):

    ---
    :secretReservationKeys:
    - :nodeUrnPrefix: "urn:wisebed:uzl1:"
      :key: "abc..."
    - :nodeUrnPrefix: "<other prefix>"
      :key: "<other secret reservation key>"
    :nodeUrns:
    - "urn:wisebed:uzl1:0x0002"
    - "urn:wisebed:uzl1:0x0003"
    - "<other node urn>"

    The section secretReservationKeys contains the information about reservations on different testbeds while the nodeUrns section contains a list of all nodes in your reservation.

  3. Write the experiment description (experiment_description.rb):

  4. require some gems:

    require 'wise_omf/client'
    require 'yaml'
    require 'base64'
  5. load the configuration:

    reservation = YAML.load_file('./reservation.yml')
  6. Initialize the reservation manager of the wise_omf helper gem.

    The manager is a factory which initializes WiseGroup objects encapsulating OMF groups containing node resources. During the initialization the ReservationManager creates one OmfEc::Group foreach node urn as well as one group for all nodes together. These groups can be used to configure nodes or a set of nodes or to request information from the nodes. Read the documentation of the ReservationManager on rubydoc.info

    WiseOMF::Client::ReservationManager.init(reservation, reservation[:nodeUrns])
  7. optional: Set a default callback for events comming from some of the node groups:

    WiseOMF::Client::ReservationManager.allNodesGroup.default_callback = lambda { |msg|
        info "Default Callback: #{msg.to_yaml}"
        # Do somthing with the message
    }

    Note: The code example registers a default callback on the group containing all nodes of the reservation. Of course it is possible to add a default callback to any other node group that can be requested from the ReservationManager.

  8. Wait for the OMF event ALL_NODES_UP. This is the real starting point of your experiment:

    onEvent :ALL_NODES_UP do
        # Write the experiment as described in the next section
    end

Writing the Experiment

At this point you have configured the OMF experiment controller and the experiment initialization is finished. All nodes are up and you are able to communicate with them.

The example in this section will teach you how to talk to a subset of all nodes in your reservation. For this purpose you'll need to create a new group dynamically by asking the ReservationManager to create it.

  1. Create a group for some nodes in your reservation:

    WiseOMF::Client::ReservationManager.createGroupForNodes(%w(<node:urn:1> <node:urn:2> ...)) { |group|
     # When this callback is called, the group was created sucessfully and you could talk to it
    }
  2. Talk to the node group in the creation callback. Ask the group whether all nodes are connected to the testbed:

    group.connected { |properties|
      # You'll get an array of responses (one for each node in your group).
      # Check if all nodes are connected
      if properties.responses.all? { |response| response.statusCode == 1 }
         # All nodes are connected. Now you can work with the nodes.
      end
    }
  3. Working with node groups: flashing an image onto all nodes of the group

    Note: Though we are talking of node groups or just groups in this tutorial, all operations are the same when talking to a single node hence you are communicating with a group containing the single node.

  4. Load the binary image from your disk:

    flash_image = File.read('<path/to/your/image.bin>')
  5. Encode the image. When flashing an image onto nodes, the testbed expects the binary image to be Base 64 encoded.

    encoded_image = Base64.encode64(flash_image)
  6. Send the flash command to the group and handle responses and progress messages from the testbed:

    group.set_image(encoded_image) { |properties|
        if properties.type.to_sym.eql? :progress
          # the message is a progress message of a single node in the group
          info "Progress of #{properties.nodeUrn}: #{properties.progress}%"
    
        elsif properties.type.to_sym.eql? :response
          # the message is a response telling us, that the flashing task was completed (or failed)
          # this message contains on response for every node in the group
          info "Finished with response: #{properties.responses.to_yaml}"
          # Make sure that further responses to the flash request are ignored:
          group.delete_callback(properties.requestId)
          # Continue with the experiment ...
        end
      }

    Note: It's recommended to put nodes that should be flashed with the same image into a group as shown in this example. This approach has some advantages as opposed to flashing every node on its own. When sending the flash request to a group of nodes, the image is only transmitted once and the testbed handles the distribution of the image. This is faster and cheaper than sending the same image multiple times.

    Note 2: Your callback will be called for every progress message of every node in your group.

  7. optional: continue with the experiment:

    At this step, your own image was flashed onto all nodes of the group. Now you should be able to communicate with the nodes by sending messages and receiving responses/ messages from the nodes.

  8. After finishing your experiment, it's good to call the done-Methods of the ReservationManager and the OmfEc::Experiment to unsubscribe from topics and free resources:

    WiseOMF::Client::ReservationManager.done
    OmfEc::Experiment.done

Putting it all together

require 'wise_omf/client'
require 'yaml'
require 'base64'

reservation = YAML.load_file('./reservation.yml')

WiseOMF::Client::ReservationManager.init(reservation, reservation[:nodeUrns])

WiseOMF::Client::ReservationManager.allNodesGroup.default_callback = lambda { |msg|
    info "Default Callback: #{msg.to_yaml}"
    # Do somthing with the message
}

onEvent :ALL_NODES_UP do
  WiseOMF::Client::ReservationManager.createGroupForNodes(%w(<node:urn:1> <node:urn:2> ...)) { |group|
    group.connected { |properties|
      # You'll get an array of responses (one for each node in your group).
      # Check if all nodes are connected
      if properties.responses.all? { |response| response.statusCode == 1 }
        # All nodes are connected. Now you can work with the nodes.
        flash_image = File.read('<path/to/your/image.bin>')
        encoded_image = Base64.encode64(flash_image)
        group.set_image(encoded_image) { |properties|
          if properties.type.to_sym.eql? :progress
            # the message is a progress message of a single node in the group
            info "Progress of #{properties.nodeUrn}: #{properties.progress}%"
          elsif properties.type.to_sym.eql? :response
            # the message is a response telling us, that the flashing task was completed (or failed)
            # this message contains on response for every node in the group
            info "Finished with response: #{properties.responses.to_yaml}"
            # Make sure that further responses to the flash request are ignored:
            group.delete_callback(properties.requestId)
            # Continue with the experiment ...

            WiseOMF::Client::ReservationManager.done
            OmfEc::Experiment.done
          end
        }
      end
    }
  }
end

Running the Experiment

At this step you have writen an experiment description as described in the last two sections. Let's execute the experiment via your shell:

omf_ec exec experiment_description.rb