= Example to Plot !LabWiki Graph from a CSV File =
== 1. On InstaGENI, use the following image which has the latest GIMI and other required Tools installed ==
{{{
Image URN: urn:publicid:IDN+instageni.illinois.edu+image+ch-geni-net:gimidev2
Image URL: https://www.instageni.illinois.edu/image_metadata.php?uuid=df9ce62b-ec1a-11e3-bc1a-000000000000
}}}
=== 1.1 Install and Execute Scripts ===
Use the following Install and Execute Scripts for GENI
{{{
}}}
For iMinds the Execute Scripts are:
{{{
}}}
For more details on what is installed in these images, go to [http://groups.geni.net/geni/wiki/GIMIv3/Documentation#Images GIMI Images]
=== 1.2 Configure RC ===
'''Note''': Only required if you install GIMI from scratch. Please skip this step if you include the Install and Execute Services as shown in 1.1
Change config file: /etc/omf_rc/config.yml
{{{
---
:uid: myhost-myslice
:uri: amqp://gimi3.casa.umass.edu
:environment: production
:debug: false
}}}
Replace the uid field with - [[BR]]
Save and run restart omf_rc
== 2. Identify Measurement Points in CSV file ==
For this example, the CSV File used is attached here (wimaxss.csv)
Each of the fields is taken as a separate measurement point for this example.
{{{
"1401394008","6C:F3:73:99:FA:1E","samsung","SPH-D710","Android","EVDO Rev 0","Sprint","99.207.13.249",-96,,"-82.8344","34.676","23.517"
"1401393251","f8:a9:d0:66:7d:78","LGE","LG-D801","Android","Wifi",,"198.21.252.5",-81,"eduroam","-82.8344","34.676","25.854"
"1401392753","6C:F3:73:99:FA:1E","samsung","SPH-D710","Android","EVDO Rev 0","Sprint","99.207.13.249",-96,,"-82.8344","34.676","17.06"
"1401392748","6C:F3:73:99:FA:1E","samsung","SPH-D710","Android","EVDO Rev 0","Sprint","99.207.13.249",-96,,"-82.8344","34.676","24.803"
"1401392619","6C:F3:73:99:FA:1E","samsung","SPH-D710","Android","EVDO Rev 0","Sprint","99.207.13.249",-101,,"-82.8344","34.676","20"
"1401392598","6C:F3:73:99:FA:1E","samsung","SPH-D710","Android","EVDO Rev 0","Sprint","99.207.13.249",-96,,"-82.8344","34.676","21.088"
}}}
The fields in order:
{{{
a) testTime: Timestamp of when the test was initiated in unix timestamp
b) mac: We use this to uniquely identify the devices. It is the MAC
address of the Wifi interface of a device.
b) make: Device manufacturer
c) model: Device model
d) platform: Operating system
e) networkType: Radio access technology
f) networkOperator: Cell network operator (null for Wifi tests)
g) ipAddress: IP that the server saw during the test
h) signalDbm: signal dBm as reported by the device's radio
i) ssid: SSID of the wifi network used (null for cell tests)
j) longitude: longitude of current location
k) latitude: latitude of current location
l) geolocationAccuracy: precision of location data in meters
}}}
== 3. Write OML4R application Script and save it on VM ==
This OML4R script has to be saved on the VM in a known location with a ".rb" extension
=== 3.1 Define a class of measurement point variables ===
This is based on the number and data type of the fields in the CSV file
{{{
class MPThroughput < OML4R::MPBase
name :wimaxss
param :unixts, :type => :string
param :ifacemac, :type => :string
param :make, :type => :string
param :model, :type => :string
param :platform, :type => :string
param :nettype, :type => :string
param :netoper, :type => :string
param :ipaddr, :type => :string
param :ssid, :type => :int64
param :longi, :type => :string
param :lat, :type => :string
param :geoLoc, :type => :string
param :metName, :type => :string
end
}}}
=== 3.2 Parse measurement fields ===
{{{
def processOutput(output)
column = output.split(",")
puts "Each line process"
# Inject the measurements into OML
puts Integer(column[8])
MPThroughput.inject("#{column[0]}", "#{column[1]}", "#{column[2]}",
"#{column[3]}", "#{column[4]}", "#{column[5]}",
"#{column[6]}", "#{column[7]}", "#{column[8]}".to_i, "#{column[9]}", "#{column[10]}", "#{column[11]}", "#{column[12]}")
end
end
}}}
=== 3.3 Specify number of lines to read ===
The log.backward() function specifies the number of lines to read while doing a file tail. In this example, we read 1 line from the file's history.
{{{
def start()
log = MyFile.new("#{@addr}")
log.interval = @if_num
log.backward(1)
puts "#{@if_num}"
log.tail { |line| print line
processOutput(line)
}
end
}}}
=== 3.4 The complete script is given below ===
{{{
#!/usr/local/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'oml4r' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
require 'oml4r'
require 'file-tail'
APPNAME = "ofstats"
class MPThroughput < OML4R::MPBase
name :wimaxss
param :unixts, :type => :string
param :ifacemac, :type => :string
param :make, :type => :string
param :model, :type => :string
param :platform, :type => :string
param :nettype, :type => :string
param :netoper, :type => :string
param :ipaddr, :type => :string
param :ssid, :type => :int64
param :longi, :type => :string
param :lat, :type => :string
param :geoLoc, :type => :string
param :metName, :type => :string
end
class OFStatsWrapper
def initialize(args)
@addr = nil
@if_num = ' '
@trema_port = ' '
@trema_path = ' '
@verbose = true
@numeric = ' '
OML4R::init(args, :appName => "#{APPNAME}_wrapper", :domain => 'foo', :collect => 'file:-') { |argParser|
argParser.banner = "Reports OpenFlow stat measurements via OML\n\n"
argParser.on("-f" , "--file_path ADDRESS", "Path where output is saved"){ |address| @addr = address }
argParser.on("-i","--interface IFNUM","Interface number"){ |if_num| @if_num ="#{if_num.to_i()}" }
argParser.on("-q", "--no-quiet ","Don't show of stats output on console"){ @verbose = false }
argParser.on("-n", "--[no]-numeric ", "No attempt twill be made to look up symbolic names for host addresses"){ @numeric ='-n' }
}
unless @addr !=nil
raise "You did not specify path of file (-p option)"
end
end
class MyFile < File
include File::Tail
end
def start()
log = MyFile.new("#{@addr}")
log.interval = @if_num
log.backward(1)
puts "#{@if_num}"
log.tail { |line| print line
processOutput(line)
}
end
def processOutput(output)
column = output.split(",")
puts "Each line process"
# Inject the measurements into OML
puts Integer(column[8])
MPThroughput.inject("#{column[0]}", "#{column[1]}", "#{column[2]}",
"#{column[3]}", "#{column[4]}", "#{column[5]}",
"#{column[6]}", "#{column[7]}", "#{column[8]}".to_i, "#{column[9]}", "#{column[10]}", "#{column[11]}", "#{column[12]}")
end
end
begin
app = OFStatsWrapper.new(ARGV)
app.start()
rescue SystemExit
rescue SignalException
puts "OFWrapper stopped."
rescue Exception => ex
puts "Error - When executing the wrapper application!"
puts "Error - Type: #{ex.class}"
puts "Error - Message: #{ex}\n\n"
# Uncomment the next line to get more info on errors
# puts "Trace - #{ex.backtrace.join("\n\t")}"
end
OML4R::close()
# Local Variables:
# mode:ruby
# End:
# vim: ft=ruby:sw=2
}}}
== 4. Write OEDL Script to Run application ==
This script has to Run from the !LabWiki Application as shown in Step 5.
=== 4.1 Define Resource Name ===
"nodec" is the name of the VM and "gimidev1" is the slicename.
{{{
defProperty('source1', "nodec-gimidev1", "ID of a resource")
}}}
=== 4.2 Specify location of CSV file on VM ===
{{{
defProperty('pathfile', "/root/wimaxss.csv", "Path to file")
}}}
=== 4.3 Define OML Application with path on VM ===
Here, you will need to define a measurement function for the measurement points you are interested in from the ones defined in step 3.1. Replace "/usr/local/bin/ofcollect.rb" with the path of your OML4R application script written in Step 3.
{{{
defApplication('ofstats') do |app|
app.description = 'Simple Definition for the of-collect application'
# Define the path to the binary executable for this application
app.binary_path = '/usr/local/bin/ofcollect.rb'
app.defProperty('target', 'Address to output file', '-f', {:type => :string})
app.defProperty("interval","Interval",'-i', {:type => :string})
app.defMeasurement('wrapper_wimaxss') do |m|
m.defMetric('ifacemac', :string)
m.defMetric('ssid',:int64)
m.defMetric('netoper', :string)
end
end
}}}
=== 4.4 Create Node Group with Application ===
The 'target' property specifies the path of the CSV file on the VM.
{{{
defGroup('Source1', property.source1) do |node|
node.addApplication("ofstats") do |app|
app.setProperty('target', property.pathfile)
app.setProperty('interval', property.intervalcol)
app.measure('wrapper_wimaxss', :samples => 1)
end
end
}}}
=== 4.5 Define parameters for Graph ===
Here, we draw two types of graphs. The first one is a Line Graph which plots SSID as a function of time for every Hardware MAC Address. [[BR]]
The second graph is a Histogram which plots SSID as a function of time for every Network Operator
Line Graph
{{{
defGraph 'SSID' do |g|
g.ms('wrapper_wimaxss').select(:oml_ts_client, :ssid, :ifacemac)
g.caption "SSID"
g.type 'line_chart3'
g.mapping :x_axis => :oml_ts_client, :y_axis => :ssid, :group_by => :ifacemac
g.xaxis :legend => 'unix_ts'
g.yaxis :legend => 'SSID', :ticks => {:format => 's'}
end
}}}
Histogram
{{{
defGraph 'SSID' do |g|
g.ms('wrapper_wimaxss').select(:oml_ts_client, :ssid, :netoper)
g.caption "SSID of Carriers"
g.type 'histogram2'
g.mapping :value => :ssid, :group_by => :netoper
g.xaxis :legend => 'Unix TS'
g.yaxis :legend => 'SSID'
end
}}}
=== 4.6 Full Script is given below ===
{{{
defProperty('source1', "nodec-gimidev1", "ID of a resource")
defProperty('intervalcol',"1", "Interval to Tail")
defProperty('pathfile', "/root/wimaxss.csv", "Path to file")
defApplication('ofstats') do |app|
app.description = 'Simple Definition for the of-collect application'
# Define the path to the binary executable for this application
app.binary_path = '/usr/local/bin/ofcollect.rb'
app.defProperty('target', 'Address to output file', '-f', {:type => :string})
app.defProperty("interval","Interval",'-i', {:type => :string})
app.defMeasurement('wrapper_wimaxss') do |m|
m.defMetric('ifacemac', :string)
m.defMetric('ssid',:int64)
m.defMetric('netoper', :string)
end
end
defGroup('Source1', property.source1) do |node|
node.addApplication("ofstats") do |app|
app.setProperty('target', property.pathfile)
app.setProperty('interval', property.intervalcol)
app.measure('wrapper_wimaxss', :samples => 1)
end
end
onEvent(:ALL_UP_AND_INSTALLED) do |event|
info "Starting the collect"
after 2 do
group('Source1').startApplications
end
after 800 do
info "Stopping the collect"
allGroups.stopApplications
Experiment.done
end
end
defGraph 'SSID' do |g|
g.ms('wrapper_wimaxss').select(:oml_ts_client, :ssid, :ifacemac)
g.caption "SSID"
g.type 'line_chart3'
g.mapping :x_axis => :oml_ts_client, :y_axis => :ssid, :group_by => :ifacemac
g.xaxis :legend => 'unix_ts'
g.yaxis :legend => 'SSID', :ticks => {:format => 's'}
end
defGraph 'SSID' do |g|
g.ms('wrapper_wimaxss').select(:oml_ts_client, :ssid, :netoper)
g.caption "SSID of Carriers"
g.type 'histogram2'
g.mapping :value => :ssid, :group_by => :netoper
g.xaxis :legend => 'Unix TS'
g.yaxis :legend => 'SSID'
end
}}}
== 5. Run Experiment in !LabWiki ==
Go to [http://gimi1.casa.umass.edu:4000 !LabWiki]
=== 5.1 Create OEDL Script in Prepare Window ===
=== 5.1.1 Copy and paste script from Step 4.6 and click on Save ===
=== 5.1.2 Click and Drag Icon on left-top corner of the Prepare Window to the Execute Window ===
== 5.2 Fill Details as shown ==
[[Image(LabWiki_SCR.png, 70%)]]
[[BR]]
[[BR]]
[[BR]]
== 5.3 Click on Start Experiment ==
You should see graphs similar to the ones as shown here.
[[Image(LW_graphs.png, 80%)]] [[BR]]