oml4r 2.10.4 → 2.10.4.20.g6503629
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/csv2oml +190 -0
- data/bin/ntpq-oml2 +200 -0
- data/bin/oml4r-multiple-channel-example +1 -1
- data/bin/oml4r-simple-example +1 -1
- data/bin/ping-oml2 +51 -37
- data/examples/oml4r-multiple-channel-example.rb +1 -1
- data/examples/oml4r-simple-example.rb +1 -1
- data/lib/oml4r.rb +28 -25
- data/lib/oml4r/version.rb +17 -1
- data/omf/README +3 -1
- data/omf/ntpq-oml2.rb +70 -0
- data/omf/{ping-oml2.app.rb → ping-oml2.rb} +0 -0
- data/oml4r.gemspec +3 -3
- metadata +17 -14
data/bin/csv2oml
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009 - 2014 National ICT Australia Limited (NICTA).
|
4
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
5
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
6
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
7
|
+
# ------------------
|
8
|
+
#
|
9
|
+
# = csv2oml
|
10
|
+
#
|
11
|
+
# == Description
|
12
|
+
#
|
13
|
+
# This tool associates an OML Measurement Point (MP) to a CSV file, then turns any
|
14
|
+
# new line from that file into an OML Measurement sample and injects it into the
|
15
|
+
# MP. It keeps monitoring the CSV file and inject any new line until it is stopped
|
16
|
+
# by Ctrl-C (or any other relevant SIGNALs). The MP definition is dynamically
|
17
|
+
# generated based on the head of CSV file (with or without header). In addition,
|
18
|
+
# the version of this tool and its execution start and termination POSIX dates are
|
19
|
+
# recorded as OML metadata to the defined MP.
|
20
|
+
#
|
21
|
+
# Example: csv2oml.rb --file X --app-name Y --mp-name Z --no-headers --interval 1
|
22
|
+
#
|
23
|
+
# --file PATH Path to the CSV file to process
|
24
|
+
# --app-name APPNAME Name of the app which generates the CSV file to process (default to 'csv2oml')
|
25
|
+
# --mp-name MPNAME Name of the Measurement Point for the CSV file to process (default to 'mp')
|
26
|
+
# --no-headers When set then do not use the 1st line to name fields/metrics (default unset)
|
27
|
+
# --interval NUMBER Interval period to check for new lines in the CSV (in second, default 1)
|
28
|
+
#
|
29
|
+
# Below are OML4R options (https://github.com/mytestbed/oml4r)
|
30
|
+
#
|
31
|
+
# --oml-id id Name to identify this app instance [undefined]
|
32
|
+
# --oml-domain domain Name of experimental domain [undefined] *EXPERIMENTAL*
|
33
|
+
# --oml-collect uri URI of server to send measurements to
|
34
|
+
# --oml-protocol p Protocol number [4]
|
35
|
+
# --oml-log-level l Log level used (info: 0 .. debug: 1)
|
36
|
+
# --oml-noop Do not collect measurements
|
37
|
+
# --oml-config file File holding OML configuration parameters
|
38
|
+
# --oml-exp-id domain Obsolescent equivalent to --oml-domain domain
|
39
|
+
# --oml-file localPath Obsolescent equivalent to --oml-collect file:localPath
|
40
|
+
# --oml-server uri Obsolescent equivalent to --oml-collect uri
|
41
|
+
# --oml-help Show this message
|
42
|
+
#
|
43
|
+
require 'rubygems'
|
44
|
+
require 'logger'
|
45
|
+
require 'csv'
|
46
|
+
|
47
|
+
NAME='csv2oml'
|
48
|
+
VERSION="1.0"
|
49
|
+
log = Logger.new(STDOUT)
|
50
|
+
log.formatter = proc do |level, time, progname, msg|
|
51
|
+
"#{time.strftime('%y%m%d_%H%M%S')} #{NAME} - #{level} - #{msg}\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
class CSV2OML
|
55
|
+
|
56
|
+
attr_reader :mp_class
|
57
|
+
|
58
|
+
def initialize(args,log)
|
59
|
+
@log = log
|
60
|
+
@app_name = NAME
|
61
|
+
@mp_name = 'mp'
|
62
|
+
@path = nil
|
63
|
+
@mp_class = nil
|
64
|
+
@headers = true
|
65
|
+
@interval = 1
|
66
|
+
@first_line = true
|
67
|
+
@metrics = []
|
68
|
+
|
69
|
+
# Unfortunately OML4R Policy is that the Application Name cannot be defined
|
70
|
+
# on the command line, and must be defined in the Application Code. While
|
71
|
+
# this makes sense for all other app, here we do not want OML to use csv2oml
|
72
|
+
# as the ID for this app, but rather use the ID of the app that generated
|
73
|
+
# the CSV. Thus we have to manually 'extract' the app name from the command
|
74
|
+
# line.
|
75
|
+
i = args.index('--app-name')
|
76
|
+
unless i.nil?
|
77
|
+
@app_name = args.delete_at(i+1)
|
78
|
+
args.delete_at(i)
|
79
|
+
end
|
80
|
+
@log.info "Using Application Name '#{@app_name}' for this OML data collection"
|
81
|
+
|
82
|
+
# Now let OML4R parse the remaining command line and do its init stuff
|
83
|
+
OML4R::init(args, :appName => @app_name) do |parser|
|
84
|
+
parser.banner=<<-text
|
85
|
+
|
86
|
+
This tool associates an OML Measurement Point (MP) to a CSV file, then turns any
|
87
|
+
new line from that file into an OML Measurement sample and injects it into the
|
88
|
+
MP. It keeps monitoring the CSV file and inject any new line until it is stopped
|
89
|
+
by Ctrl-C (or any other relevant SIGNALs). The MP definition is dynamically
|
90
|
+
generated based on the head of CSV file (with or without header). In addition,
|
91
|
+
the version of this tool and its execution start and termination POSIX dates are
|
92
|
+
recorded as OML metadata to the defined MP.\n
|
93
|
+
Example: csv2oml.rb --file X --app-name Y --mp-name Z --no-headers --interval 1\n
|
94
|
+
text
|
95
|
+
parser.on("--file PATH", "Path to the CSV file to process") { |name| @path = name }
|
96
|
+
parser.on("--app-name APPNAME", "Name of the app which generates the CSV file to process (default to 'csv2oml')") { |name| @app_name = name }
|
97
|
+
parser.on("--mp-name MPNAME", "Name of the Measurement Point for the CSV file to process (default to 'mp')") { |name| @mp_name = name }
|
98
|
+
parser.on("--no-headers", "When set then do not use the 1st line to name fields/metrics (default unset)") { @headers = false }
|
99
|
+
parser.on("--interval NUMBER", "Interval period to check for new lines in the CSV (in second, default 1)") { |i| @interval = i }
|
100
|
+
parser.on_tail("--version", "Show version number") { $stderr.puts "#{NAME} - version #{VERSION}"; exit }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def start()
|
105
|
+
# Open the CSV file and monitor it
|
106
|
+
# This will continue until SIGTERM or Ctrl-C are received
|
107
|
+
raise "Missing CSV file path (option '--file')" if @path.nil?
|
108
|
+
@log.info "Monitoring CSV file '#{@path}' (SIGTERM or Ctrl-C to exit)"
|
109
|
+
File.open(@path) do |f|
|
110
|
+
f.extend(File::Tail)
|
111
|
+
f.interval = @interval
|
112
|
+
f.tail { |line| process(line) }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def process(line)
|
117
|
+
line = build_measurement_point(line) if @mp_class.nil?
|
118
|
+
unless line.nil?
|
119
|
+
parsed_line = CSV.parse(line,{:converters => :numeric})[0]
|
120
|
+
@mp_class.inject(*parsed_line)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def build_measurement_point(line)
|
125
|
+
# First line in the file and headers is true, so use this line as metrics
|
126
|
+
if (@headers && @first_line)
|
127
|
+
@metrics = line.chomp.split(',')
|
128
|
+
# Some checks: get rid of quotes, make sure fields are not numbers
|
129
|
+
@metrics = @metrics.map { |e| e.chomp('"').reverse.chomp('"').reverse }
|
130
|
+
@metrics = @metrics.map { |e| e.chomp("'").reverse.chomp("'").reverse }
|
131
|
+
@metrics.each { |e| raise "Cannot create MP! Invalid metric name '#{e}' in CSV header '#{@metrics}'!" if e.match(/\A[+-]?\d+?(\.\d+)?\Z/) }
|
132
|
+
@first_line = false
|
133
|
+
return nil
|
134
|
+
end
|
135
|
+
# Second line in the file or First line but headers is false
|
136
|
+
# Then use this line to determine the OML types for the MP
|
137
|
+
types = []
|
138
|
+
parsed_line = CSV.parse(line,{:converters => :numeric})[0]
|
139
|
+
# Only support a subset of OML's supported type, as there is no standard
|
140
|
+
# way to tell from a CSV record if 'true' is meant to be a boolean or a
|
141
|
+
# string, same goes for GUIDs which OML support
|
142
|
+
parsed_line.each do |v|
|
143
|
+
case v.class.to_s.to_sym
|
144
|
+
when :Fixnum
|
145
|
+
types << :int32
|
146
|
+
when :Bignum
|
147
|
+
types << :int64
|
148
|
+
when :Float
|
149
|
+
types << :double
|
150
|
+
else
|
151
|
+
types << :string
|
152
|
+
end
|
153
|
+
end
|
154
|
+
# Make sure with have names for the metrics of this MP
|
155
|
+
parsed_line.length.times { |i| @metrics << "V#{i}"} if @metrics.empty?
|
156
|
+
# Sanity check
|
157
|
+
raise "Cannot create MP! Size of defined metrics do not match size of a sample!" if @metrics.length != types.length
|
158
|
+
# Now define the new MP
|
159
|
+
@mp_class = Class.new(OML4R::MPBase)
|
160
|
+
@mp_class.name(@mp_name)
|
161
|
+
@metrics.each_index { |i| @mp_class.param(@metrics[i].to_sym, :type => types[i].to_sym) }
|
162
|
+
@first_line = false
|
163
|
+
@log.info "Defined MP '#{@mp_name}' (OML table name: '#{@app_name}_#{@mp_name}') "+
|
164
|
+
"with metrics: #{@metrics.map {|m| "#{m} (#{types[@metrics.index(m)]})" }.join(', ')}"
|
165
|
+
@mp_class.inject_metadata('csv2oml_version',VERSION)
|
166
|
+
@mp_class.inject_metadata('csvfile',@path)
|
167
|
+
@mp_class.inject_metadata('posix_start_date',Time.now.to_i)
|
168
|
+
return line
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Apps main entry...
|
173
|
+
begin
|
174
|
+
require 'oml4r'
|
175
|
+
require 'file-tail'
|
176
|
+
app = CSV2OML.new(ARGV,log)
|
177
|
+
app.start
|
178
|
+
rescue LoadError => ex
|
179
|
+
log.error "Missing library! Try running 'gem install #{ex.to_s.split[-1]}' (original error: #{ex}) "
|
180
|
+
rescue SystemExit
|
181
|
+
rescue SignalException
|
182
|
+
log.info "#{NAME} stopped."
|
183
|
+
rescue Exception => ex
|
184
|
+
log.error "#{ex.class} - #{ex}\n\n"
|
185
|
+
# Uncomment the next line to get more info on errors
|
186
|
+
#log.error "Trace - #{ex.backtrace.join("\n\t")}"
|
187
|
+
ensure
|
188
|
+
app.mp_class.inject_metadata('posix_end_date',Time.now.to_i) unless (app.nil? || app.mp_class.nil?)
|
189
|
+
end
|
190
|
+
OML4R::close()
|
data/bin/ntpq-oml2
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# OML4R wrapper for ntpq
|
4
|
+
#
|
5
|
+
# This application runs the system ntpq -p -n, parses its output and reports the
|
6
|
+
# measurements via OML
|
7
|
+
#
|
8
|
+
# Author: Olivier Mehani <olivier.mehani@nicta.com.au>, (C) 2014
|
9
|
+
# Copyright (c) 2014 National ICT Australia (NICTA)
|
10
|
+
#
|
11
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
12
|
+
# of this software and associated documentation files (the "Software"), to deal
|
13
|
+
# in the Software without restriction, including without limitation the rights
|
14
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
15
|
+
# copies of the Software, and to permit persons to whom the Software is
|
16
|
+
# furnished to do so, subject to the following conditions:
|
17
|
+
#
|
18
|
+
# The above copyright notice and this permission notice shall be included in
|
19
|
+
# all copies or substantial portions of the Software.
|
20
|
+
#
|
21
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
22
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
23
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
24
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
25
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
26
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
27
|
+
# THE SOFTWARE.
|
28
|
+
#
|
29
|
+
|
30
|
+
require 'rubygems'
|
31
|
+
require 'oml4r'
|
32
|
+
|
33
|
+
@@bin = "ntpq"
|
34
|
+
@@binopt = "-p -n"
|
35
|
+
@@appname = @@bin + "-oml2"
|
36
|
+
# XXX: if when is expressed in days, we need to rescale it, see MP.cleanup
|
37
|
+
@@regex = /^(?<rtype>\*|#|o|\+|x|.|-| )(?<remote>[^\s]+)\s+(?<refid>[^\s]+)\s+(?<stratum>\d+)\s+(?<type>l|u|m|b|-)\s+(?<when>\d+d?|-})\s+(?<poll>\d+)\s+(?<reach>\d+)\s+(?<delay>(\d|\.)+)\s+(?<offset>-?(\d|\.)+)\s+(?<jitter>(\d|\.)+)$/
|
38
|
+
|
39
|
+
# See [0] for explanations of the fields
|
40
|
+
# [rtype]remote, refid, st[ratum], t[ype], when, poll, reach, delay, offset, jitter [or dispersion]
|
41
|
+
# [0] http://h30499.www3.hp.com/t5/System-Administration/Interpreting-NTPQ-output/m-p/3616540/highlight/true#M235154
|
42
|
+
class MP < OML4R::MPBase
|
43
|
+
name @@bin
|
44
|
+
|
45
|
+
param :rtype, :type => :string #
|
46
|
+
# Character that may be before hostname:
|
47
|
+
# * indicates the current synchronization source.
|
48
|
+
# # indicates that the host is selected for synchronization, but distance from the
|
49
|
+
# host to the server exceeds the maximum value.
|
50
|
+
# o indicates that the host is selected for synchronization, and the PPS signal is
|
51
|
+
# in use.
|
52
|
+
# + indicates the host included in the final synchronization selection set.
|
53
|
+
# x indicates that the host is the designated false ticker by the intersection
|
54
|
+
# algorithm.
|
55
|
+
# . indicates that the host is selected from the end of the candidate list.
|
56
|
+
# - indicates a host discarded by the clustering algorithm.
|
57
|
+
# blank indicates a host is discarded due to high stratum and/or failed sanity
|
58
|
+
# checks.
|
59
|
+
|
60
|
+
param :remote, :type => :string # IP address of host
|
61
|
+
param :refid, :type => :string # source of synchronisation
|
62
|
+
param :stratum, :type => :uint32 # stratum level of the host
|
63
|
+
|
64
|
+
param :type, :type => :string # type of host
|
65
|
+
# l local (such as a GPS clock)
|
66
|
+
# u unicast (this is the common type)
|
67
|
+
# m multicast
|
68
|
+
# b broadcast
|
69
|
+
# - netaddr (usually 0)
|
70
|
+
|
71
|
+
param :when, :type => :uint32 # number of seconds passed since the remote host response [s]
|
72
|
+
param :poll, :type => :uint32 # polling interval to the remote host [s]
|
73
|
+
param :reach, :type => :uint32 # 8-bit shift register of reach attempts
|
74
|
+
param :delay, :type => :double # round trip time [ms]
|
75
|
+
param :offset, :type => :double # time difference between server and client [ms]
|
76
|
+
param :jitter, :type => :double # difference in the offset measurement between two samples [ms]
|
77
|
+
end
|
78
|
+
|
79
|
+
# XXX: OML4R should allow support for REs, and create a match function per MP
|
80
|
+
if not defined? MP.match
|
81
|
+
def MP.match(row)
|
82
|
+
cleanup(@@regex.match(row))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
if not defined? MP.cleanup
|
86
|
+
def MP.cleanup(match)
|
87
|
+
return if match.nil?
|
88
|
+
if match["when"].include? "d"
|
89
|
+
# Convert the MatchData into a Hash so we can overwrite it; this conserves
|
90
|
+
# the assumption that match[0] is the full string that matched; if other
|
91
|
+
# cleanup is needed, this should be done outside of this conditional
|
92
|
+
match = { :MatchData => match[0] }.merge(Hash[match.names.zip(match.captures)])
|
93
|
+
|
94
|
+
match["when"] = "#{match["when"].to_i * 86400}"
|
95
|
+
match.values
|
96
|
+
else
|
97
|
+
match
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Wrapper
|
103
|
+
attr_accessor :loop_interval
|
104
|
+
|
105
|
+
def initialize(args)
|
106
|
+
@binio = nil
|
107
|
+
@verbose = true
|
108
|
+
@leftover = []
|
109
|
+
@loop_interval = 0
|
110
|
+
|
111
|
+
begin
|
112
|
+
@leftover = OML4R::init(args, :appName => @@bin) do |argParser|
|
113
|
+
argParser.banner = "Runs the system #{@@bin}#{(@@binopt.nil?)?"":" (#{@@binopt})"} and reports measurements via OML\n Use -h or --help for a list of options\n\n"
|
114
|
+
argParser.on("-l","--loop-interval NUMBER","Interval between runs (seconds)"){ |interval| @loop_interval = interval.to_i()}
|
115
|
+
argParser.on("-q","--[no]-quiet ","Don't show #{@@bin} output on the console"){ @verbose = false }
|
116
|
+
end
|
117
|
+
|
118
|
+
rescue OML4R::MissingArgumentException => ex
|
119
|
+
OML4R.logger.warn "#{@@appname}: #{ex}"
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
def process_output(row)
|
125
|
+
if not (parse = MP.match(row)).nil? # One sample
|
126
|
+
MP.inject(*parse[1..-1])
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def run()
|
131
|
+
@binio = IO.popen("#{@@bin} #{@@binopt} #{(@leftover.nil?)?"":@leftover.join(' ')}")
|
132
|
+
while true
|
133
|
+
row = @binio.readline
|
134
|
+
puts row if @verbose
|
135
|
+
process_output(row)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def start()
|
140
|
+
return if not @binio.nil?
|
141
|
+
|
142
|
+
begin
|
143
|
+
run
|
144
|
+
rescue EOFError
|
145
|
+
@binio.close
|
146
|
+
@binio = nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def stop()
|
151
|
+
@loop_interval = 0
|
152
|
+
return if @binio.nil?
|
153
|
+
# Kill the ping process, which will result in EOFError from ping()
|
154
|
+
Process.kill("INT", @binio.pid)
|
155
|
+
@binio.close
|
156
|
+
@binio = nil
|
157
|
+
end
|
158
|
+
|
159
|
+
end #end of class
|
160
|
+
|
161
|
+
begin
|
162
|
+
OML4R.logger.info "#{@@appname} #{OML4R::VERSION}"
|
163
|
+
|
164
|
+
app = Wrapper.new(ARGV)
|
165
|
+
|
166
|
+
# Handle Ctrl+C and OMF's SIGTERM
|
167
|
+
Signal.trap("INT") { app.stop }
|
168
|
+
Signal.trap("TERM") { app.stop }
|
169
|
+
|
170
|
+
# Handle for OMF's 'exit' command
|
171
|
+
a = Thread.new do
|
172
|
+
$stdin.each do |line|
|
173
|
+
if /^exit/ =~ line
|
174
|
+
Process.kill("INT", 0)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
while true
|
180
|
+
app.start
|
181
|
+
if app.loop_interval > 0
|
182
|
+
sleep app.loop_interval
|
183
|
+
else
|
184
|
+
exit
|
185
|
+
end
|
186
|
+
end
|
187
|
+
# XXX: Sleep for one second to let OML4R send the remaining data (see comments
|
188
|
+
# in #1485)
|
189
|
+
sleep 1
|
190
|
+
rescue Interrupt
|
191
|
+
rescue SystemExit
|
192
|
+
OML4R.close
|
193
|
+
rescue Exception => ex
|
194
|
+
OML4R.logger.error "#{@@appname}: #{ex}"
|
195
|
+
end
|
196
|
+
|
197
|
+
# Local Variables:
|
198
|
+
# mode:ruby
|
199
|
+
# End:
|
200
|
+
# vim: ft=ruby:sw=2
|
data/bin/oml4r-simple-example
CHANGED
data/bin/ping-oml2
CHANGED
@@ -6,9 +6,9 @@
|
|
6
6
|
# measurements via OML
|
7
7
|
#
|
8
8
|
# Author: Christoph Dwertmann <christoph.dwertmann@nicta.com.au>, (C) 2012-2013
|
9
|
-
# Author: Olivier Mehani <olivier.mehani@nicta.com.au>, (C) 2012-
|
9
|
+
# Author: Olivier Mehani <olivier.mehani@nicta.com.au>, (C) 2012-2014
|
10
10
|
#
|
11
|
-
# Copyright (c) 2012 National ICT Australia (NICTA)
|
11
|
+
# Copyright (c) 2012--2014 National ICT Australia (NICTA)
|
12
12
|
#
|
13
13
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
14
14
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -32,8 +32,11 @@
|
|
32
32
|
require 'rubygems'
|
33
33
|
require 'oml4r'
|
34
34
|
|
35
|
+
@@bin = "ping"
|
36
|
+
@@appname = @@bin + "-oml2"
|
37
|
+
|
35
38
|
class MPStat < OML4R::MPBase
|
36
|
-
name
|
39
|
+
name @@bin
|
37
40
|
param :dest_addr, :type => :string
|
38
41
|
param :ttl, :type => :uint32
|
39
42
|
param :rtt, :type => :double
|
@@ -62,24 +65,32 @@ class PingWrapper
|
|
62
65
|
|
63
66
|
def initialize(args)
|
64
67
|
@addr = nil
|
68
|
+
@broadcast = nil
|
65
69
|
@count = ''
|
66
70
|
@interval = ''
|
67
71
|
@verbose = true
|
68
72
|
@inet6 = ''
|
69
73
|
@numeric = ''
|
70
|
-
@
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
@binio = nil
|
75
|
+
|
76
|
+
begin
|
77
|
+
leftover = OML4R::init(args, :appName => @@bin) do |argParser|
|
78
|
+
argParser.banner = "Runs the system ping and reports measurements via OML\n Use -h or --help for a list of options\n\n"
|
79
|
+
argParser.on("-a","--dest_addr ADDRESS","Address to ping (the -a switch is optional)") { |address| @addr = address.to_s() }
|
80
|
+
argParser.on("-b","--broadcast","Allow pinging a broadcast address") { @broadcast ='-b' }
|
81
|
+
argParser.on("-c","--count NUMBER","Number of pings (default: infinite)"){ |count| @count = "-c #{count.to_i()}"}
|
82
|
+
argParser.on("-i","--interval NUMBER","Interval between pings (seconds)"){ |interval| @interval = "-i #{interval.to_i()}"}
|
83
|
+
argParser.on("-q","--[no]-quiet ","Don't show ping output on the console"){ @verbose = false }
|
84
|
+
argParser.on("-6","--[no]-inet6 ","Use ping6 rather than ping"){ @inet6 = "6"}
|
85
|
+
argParser.on("-n","--[no]-numeric ","No attempt will be made to lookup symbolic names for host addresses"){ @numeric = '-n' }
|
86
|
+
end
|
87
|
+
|
88
|
+
rescue OML4R::MissingArgumentException => ex
|
89
|
+
OML4R.logger.warn "#{@@appname}: #{ex}"
|
90
|
+
leftover = []
|
80
91
|
end
|
81
92
|
|
82
|
-
if @addr.nil?
|
93
|
+
if @addr.nil? and not leftover.nil?
|
83
94
|
if leftover.length > 0
|
84
95
|
@addr = leftover[0]
|
85
96
|
else
|
@@ -110,56 +121,59 @@ class PingWrapper
|
|
110
121
|
end
|
111
122
|
end
|
112
123
|
|
113
|
-
def
|
114
|
-
@
|
124
|
+
def run()
|
125
|
+
@binio = IO.popen("#{@@bin}#{@inet6} #{@numeric} #{@count} #{@interval} #{@broadcast} #{@addr}")
|
115
126
|
while true
|
116
|
-
row = @
|
127
|
+
row = @binio.readline
|
117
128
|
puts row if @verbose
|
118
129
|
process_output(row)
|
119
130
|
end
|
120
131
|
end
|
121
132
|
|
122
133
|
def start()
|
123
|
-
return if not @
|
124
|
-
|
125
|
-
# Handle for OMF's 'exit' command
|
126
|
-
a = Thread.new do
|
127
|
-
$stdin.each do |line|
|
128
|
-
if /^exit/ =~ line
|
129
|
-
Process.kill("INT", 0)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# Handle Ctrl+C and OMF's SIGTERM
|
135
|
-
Signal.trap("INT", stop )
|
136
|
-
Signal.trap("TERM", stop)
|
137
|
-
|
134
|
+
return if not @binio.nil?
|
138
135
|
begin
|
139
|
-
|
136
|
+
run
|
140
137
|
rescue EOFError
|
141
138
|
# This error is expected
|
142
139
|
end
|
143
140
|
end
|
144
141
|
|
145
142
|
def stop()
|
146
|
-
return if @
|
143
|
+
return if @binio.nil?
|
147
144
|
# Kill the ping process, which will result in EOFError from ping()
|
148
|
-
Process.kill("INT", @
|
145
|
+
Process.kill("INT", @binio.pid)
|
149
146
|
end
|
150
147
|
|
151
148
|
end #end of class
|
152
149
|
|
153
150
|
begin
|
154
|
-
|
151
|
+
OML4R.logger.info "#{@@appname} #{OML4R::VERSION}"
|
152
|
+
|
155
153
|
app = PingWrapper.new(ARGV)
|
154
|
+
|
155
|
+
# Handle Ctrl+C and OMF's SIGTERM
|
156
|
+
Signal.trap("INT") { app.stop }
|
157
|
+
Signal.trap("TERM") { app.stop }
|
158
|
+
|
159
|
+
# Handle for OMF's 'exit' command
|
160
|
+
a = Thread.new do
|
161
|
+
$stdin.each do |line|
|
162
|
+
if /^exit/ =~ line
|
163
|
+
Process.kill("INT", 0)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
156
168
|
app.start()
|
157
169
|
# XXX: Sleep for one second to let OML4R send the remaining data (see comments
|
158
170
|
# in #1485)
|
159
171
|
sleep 1
|
160
172
|
rescue Interrupt
|
173
|
+
rescue SystemExit
|
174
|
+
OML4R.close
|
161
175
|
rescue Exception => ex
|
162
|
-
|
176
|
+
OML4R.logger.error "#{@@appname}: #{ex}"
|
163
177
|
end
|
164
178
|
|
165
179
|
# Local Variables:
|
data/lib/oml4r.rb
CHANGED
@@ -366,6 +366,7 @@ module OML4R
|
|
366
366
|
omlConfigFile = nil
|
367
367
|
|
368
368
|
if argv
|
369
|
+
OML4R.logger.debug "ARGV: #{argv.inspect}"
|
369
370
|
# Create a new Parser for the command line
|
370
371
|
op = OptionParser.new
|
371
372
|
# Include the definition of application's specific arguments
|
@@ -376,7 +377,8 @@ module OML4R
|
|
376
377
|
op.on("--oml-collect uri", "URI of server to send measurements to") { |u| opts[:omlCollectUri] = u }
|
377
378
|
op.on("--oml-protocol p", "Protocol number [#{OML4R::DEF_PROTOCOL}]") { |l| opts[:protocol] = l.to_i }
|
378
379
|
op.on("--oml-log-level l", "Log level used (info: 0 .. debug: 1)") { |l| OML4R.logger.level = 1 - l.to_i }
|
379
|
-
op.on("--oml-noop", "Do not collect measurements") {
|
380
|
+
op.on("--oml-noop", "Do not collect measurements") { OML4R.logger.info "OML reporting disabled from command line"
|
381
|
+
return }
|
380
382
|
op.on("--oml-config file", "File holding OML configuration parameters") { |f| omlConfigFile = f }
|
381
383
|
op.on("--oml-exp-id domain", "Obsolescent equivalent to --oml-domain domain") { |name|
|
382
384
|
opts[:domain] = name
|
@@ -390,9 +392,12 @@ module OML4R
|
|
390
392
|
opts[:omlCollectUri] = "#{u}"
|
391
393
|
OML4R.logger.warn "Option --oml-server is getting deprecated; please use '--oml-collect #{opts[:omlCollectUri]}' instead"
|
392
394
|
}
|
393
|
-
op.on_tail("--oml-help", "Show this message") { $stderr.puts op
|
395
|
+
op.on_tail("--oml-help", "Show this message") { $stderr.puts op }
|
394
396
|
# XXX: This should be set by the application writer, not the command line
|
395
397
|
#op.on("--oml-appid APPID", "Application ID for OML [#{appName || 'undefined'}] *EXPERIMENTAL*") { |name| appID = name }
|
398
|
+
unless opts[:appName]
|
399
|
+
raise MissingArgumentException.new 'OML4R: Missing :appName in application code!'
|
400
|
+
end
|
396
401
|
|
397
402
|
# Now parse the command line
|
398
403
|
rest = op.parse(argv)
|
@@ -400,28 +405,27 @@ module OML4R
|
|
400
405
|
# give the app a chance to fix missing parameters
|
401
406
|
opts[:afterParse].call(opts)
|
402
407
|
end
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
end
|
408
|
+
|
409
|
+
# Parameters in OML config file takes precedence
|
410
|
+
unless omlConfigFile.nil?
|
411
|
+
f = File.open(omlConfigFile, 'r')
|
412
|
+
f.each_line do |l|
|
413
|
+
d = l[/.*experiment=["']([^"']*)/,1]
|
414
|
+
opts[:domain] = d if d
|
415
|
+
d = l[/.*domain=["']([^"']*)/,1]
|
416
|
+
opts[:domain] = d if d
|
417
|
+
i = l[/.*id=["']([^"']*)/,1]
|
418
|
+
opts[:nodeID] = i if i
|
419
|
+
u = l[/.*url=["']([^"']*)/,1]
|
420
|
+
opts[:omlCollectUri] = u if u
|
421
|
+
end
|
422
|
+
f.close
|
423
|
+
end
|
420
424
|
end
|
421
425
|
|
422
|
-
|
426
|
+
unless opts[:nodeID]
|
423
427
|
begin
|
424
|
-
# Create a default nodeID by
|
428
|
+
# Create a default nodeID by concatenating the local hostname with the process ID
|
425
429
|
hostname = nil
|
426
430
|
begin
|
427
431
|
#hostname = Socket.gethostbyname(Socket.gethostname)[0]
|
@@ -436,12 +440,11 @@ module OML4R
|
|
436
440
|
end
|
437
441
|
end
|
438
442
|
unless opts[:nodeID]
|
439
|
-
raise MissingArgumentException.new 'OML4R: Missing values for parameter :nodeID (--oml-id)'
|
443
|
+
raise MissingArgumentException.new 'OML4R: Missing values for parameter :nodeID (--oml-id, OML_ID)'
|
440
444
|
end
|
441
445
|
end
|
442
|
-
|
443
|
-
|
444
|
-
raise MissingArgumentException.new 'OML4R: Missing values for parameters :domain (--oml-domain) or :appName (in code)!'
|
446
|
+
unless opts[:domain]
|
447
|
+
raise MissingArgumentException.new 'OML4R: Missing values for parameter :domain (--oml-domain, OML_DOMAIN)!'
|
445
448
|
end
|
446
449
|
|
447
450
|
# Set a default collection URI if nothing has been specified
|
data/lib/oml4r/version.rb
CHANGED
@@ -5,7 +5,23 @@
|
|
5
5
|
# ------------------
|
6
6
|
|
7
7
|
module OML4R
|
8
|
-
|
8
|
+
|
9
|
+
def self.version_of(name)
|
10
|
+
git_tag = `git describe --tags 2> /dev/null`.chomp
|
11
|
+
git_root = `git rev-parse --show-toplevel 2> /dev/null`.chomp
|
12
|
+
gem_v = Gem.loaded_specs[name].version.to_s rescue '0.0.0'
|
13
|
+
|
14
|
+
# Not in a development environment or git not present
|
15
|
+
if git_root != File.absolute_path("#{File.dirname(__FILE__)}/../../") || git_tag.empty?
|
16
|
+
gem_v
|
17
|
+
else
|
18
|
+
git_tag.gsub(/-/, '.').gsub(/^v/, '')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
VERSION = version_of('oml4r')
|
9
23
|
VERSION_STRING = "OML4R Client V#{VERSION}"
|
10
24
|
COPYRIGHT = "Copyright 2009-2014, NICTA"
|
11
25
|
end
|
26
|
+
|
27
|
+
# vim: ft=ruby:sw=2
|
data/omf/README
CHANGED
@@ -1 +1,3 @@
|
|
1
|
-
This directory contains OMF application definitions for the applications that
|
1
|
+
This directory contains OMF application definitions for the applications that
|
2
|
+
ship with the oml4r gem. To use it, copy the application definition file into
|
3
|
+
the ame directory as your OEDL experiment and run the EC from there.
|
data/omf/ntpq-oml2.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Copyright 2014 National ICT Australia (NICTA)
|
2
|
+
#
|
3
|
+
# This software may be used and distributed solely under the terms of
|
4
|
+
# the MIT license (License). You should find a copy of the License in
|
5
|
+
# COPYING or at http://opensource.org/licenses/MIT. By downloading or
|
6
|
+
# using this software you accept the terms and the liability disclaimer
|
7
|
+
# in the License.
|
8
|
+
#
|
9
|
+
defApplication('oml:app:ntpq', 'ntpq') do |a|
|
10
|
+
|
11
|
+
a.version(2, 10, 4)
|
12
|
+
a.shortDescription = "Wrapper around ntpq -p -n"
|
13
|
+
a.description = %{This application runs the system ntpq, parses its output and
|
14
|
+
reports the measurements via OML
|
15
|
+
}
|
16
|
+
a.path = "/usr/local/bin/ntpq-oml2"
|
17
|
+
|
18
|
+
# XXX: -n and -p are implied, and -i is irrelevant for automated use
|
19
|
+
a.defProperty('force-v4', 'Force DNS resolution of following host names on the command line to the IPv4 namespace',
|
20
|
+
-4, :type => :boolean)
|
21
|
+
a.defProperty('force-v6', 'Force DNS resolution of following host names on the command line to the IPv6 namespace',
|
22
|
+
-6, :type => :boolean)
|
23
|
+
a.defProperty('count', 'Interactive format command and added to the list of commands to be executed on the specified host',
|
24
|
+
'-c', :type => :string)
|
25
|
+
# These options are specific to the instrumentation
|
26
|
+
a.defProperty('loop-interval', 'Interval between runs (seconds)',
|
27
|
+
'-l', :type => :integer, :unit => 'seconds')
|
28
|
+
a.defProperty('quiet', 'Don\'t show ntpq output on the console',
|
29
|
+
'-q', :type => :boolean)
|
30
|
+
|
31
|
+
a.defMeasurement('ntpq') do |m|
|
32
|
+
m.defMetric('rtype',:string)
|
33
|
+
m.defMetric('remote',:string)
|
34
|
+
m.defMetric('refid',:string)
|
35
|
+
m.defMetric('stratum',:uint32)
|
36
|
+
m.defMetric('type',:string)
|
37
|
+
m.defMetric('when',:uint32)
|
38
|
+
m.defMetric('poll',:uint32)
|
39
|
+
m.defMetric('reach',:uint32)
|
40
|
+
m.defMetric('delay',:double)
|
41
|
+
m.defMetric('offset',:double)
|
42
|
+
m.defMetric('jitter',:double)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
# Example use with OMF:
|
48
|
+
#defProperty('node', "node1-1.grid.orbit-lab.org", "ID of a resource")
|
49
|
+
#
|
50
|
+
#defGroup('Source', property.node) do |node|
|
51
|
+
# node.addApplication("oml:app:ntpq") do |app|
|
52
|
+
# app.setProperty('loop-interval', 10)
|
53
|
+
# app.setProperty('quiet', true)
|
54
|
+
# app.measure('ntpq', :samples => 1)
|
55
|
+
# end
|
56
|
+
#end
|
57
|
+
#
|
58
|
+
#onEvent(:ALL_UP_AND_INSTALLED) do |event|
|
59
|
+
# info "Starting ntpq"
|
60
|
+
# group('Source').startApplications
|
61
|
+
# wait 6
|
62
|
+
# info "Stopping ntpq"
|
63
|
+
# group('Source').stopApplications
|
64
|
+
# Experiment.done
|
65
|
+
#end
|
66
|
+
|
67
|
+
# Local Variables:
|
68
|
+
# mode:ruby
|
69
|
+
# End:
|
70
|
+
# vim: ft=ruby:sw=2
|
File without changes
|
data/oml4r.gemspec
CHANGED
@@ -5,9 +5,9 @@ require "oml4r/version"
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.authors = ["NICTA"]
|
8
|
-
gem.email =
|
9
|
-
gem.
|
10
|
-
gem.
|
8
|
+
gem.email = "oml-user@lists.nicta.com.au"
|
9
|
+
gem.summary= "Simple OML client library and applications for Ruby"
|
10
|
+
gem.description= "This is a simple client library for OML which does not use liboml2 and its filters, but connects directly to the server using the +text+ protocol. User can use this library to create ruby applications which can send measurement to the OML collection server. The gem ships with some example applications."
|
11
11
|
gem.homepage = "http://oml.mytestbed.net"
|
12
12
|
|
13
13
|
# ls-files won't work in VPATH builds;
|
metadata
CHANGED
@@ -1,20 +1,24 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oml4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.10.4
|
5
|
-
prerelease:
|
4
|
+
version: 2.10.4.20.g6503629
|
5
|
+
prerelease: 10
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- NICTA
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-09-22 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description:
|
15
|
-
|
16
|
-
|
14
|
+
description: This is a simple client library for OML which does not use liboml2 and
|
15
|
+
its filters, but connects directly to the server using the +text+ protocol. User
|
16
|
+
can use this library to create ruby applications which can send measurement to the
|
17
|
+
OML collection server. The gem ships with some example applications.
|
18
|
+
email: oml-user@lists.nicta.com.au
|
17
19
|
executables:
|
20
|
+
- csv2oml
|
21
|
+
- ntpq-oml2
|
18
22
|
- oml4r-multiple-channel-example
|
19
23
|
- oml4r-neuca-beacon
|
20
24
|
- oml4r-orca-beacon
|
@@ -32,6 +36,8 @@ files:
|
|
32
36
|
- LICENSE.txt
|
33
37
|
- README.md
|
34
38
|
- Rakefile
|
39
|
+
- bin/csv2oml
|
40
|
+
- bin/ntpq-oml2
|
35
41
|
- bin/oml4r-multiple-channel-example
|
36
42
|
- bin/oml4r-neuca-beacon
|
37
43
|
- bin/oml4r-orca-beacon
|
@@ -56,7 +62,8 @@ files:
|
|
56
62
|
- lib/oml4r/logging/oml4r_appender.rb
|
57
63
|
- lib/oml4r/version.rb
|
58
64
|
- omf/README
|
59
|
-
- omf/
|
65
|
+
- omf/ntpq-oml2.rb
|
66
|
+
- omf/ping-oml2.rb
|
60
67
|
- oml4r.gemspec
|
61
68
|
homepage: http://oml.mytestbed.net
|
62
69
|
licenses:
|
@@ -74,17 +81,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
74
81
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
82
|
none: false
|
76
83
|
requirements:
|
77
|
-
- - ! '
|
84
|
+
- - ! '>'
|
78
85
|
- !ruby/object:Gem::Version
|
79
|
-
version:
|
86
|
+
version: 1.3.1
|
80
87
|
requirements: []
|
81
88
|
rubyforge_project:
|
82
89
|
rubygems_version: 1.8.23
|
83
90
|
signing_key:
|
84
91
|
specification_version: 3
|
85
|
-
summary:
|
86
|
-
its filters, but connects directly to the server using the +text+ protocol. User
|
87
|
-
can use this library to create ruby applications which can send measurement to the
|
88
|
-
OML collection server. The gem ships with some example applications."]'
|
92
|
+
summary: Simple OML client library and applications for Ruby
|
89
93
|
test_files: []
|
90
|
-
has_rdoc:
|