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 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
@@ -63,7 +63,7 @@ begin
63
63
  op.on("--oml-ch2 URL", "Set destination for Channel 2 [#{ch2.url}]") { |url| ch2.url = url }
64
64
  end
65
65
  rescue OML4R::MissingArgumentException => mex
66
- $stderr.puts mex
66
+ OML4R.logger.error "oml4r-multiple-channel-example: #{mex}"
67
67
  exit
68
68
  end
69
69
 
@@ -48,7 +48,7 @@ opts = {:appName => 'oml4rSimpleExample',
48
48
  begin
49
49
  OML4R::init(ARGV, opts)
50
50
  rescue OML4R::MissingArgumentException => mex
51
- $stderr.puts mex
51
+ OML4R.logger.error "oml4r-simple-example: #{mex}"
52
52
  exit
53
53
  end
54
54
 
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-2013
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 :ping
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
- @pingio = nil
71
-
72
- leftover = OML4R::init(args, :appName => 'ping') do |argParser|
73
- argParser.banner = "Runs the system ping and reports measurements via OML\n Use -h or --help for a list of options\n\n"
74
- argParser.on("-a","--dest_addr ADDRESS","Address to ping (the -a switch is optional)") { |address| @addr = address.to_s() }
75
- argParser.on("-c","--count NUMBER","Number of pings (default: infinite)"){ |count| @count = "-c #{count.to_i()}"}
76
- argParser.on("-i","--interval NUMBER","Interval between pings (seconds)"){ |interval| @interval = "-i #{interval.to_i()}"}
77
- argParser.on("-q","--[no]-quiet ","Don't show ping output on the console"){ @verbose = false }
78
- argParser.on("-6","--[no]-inet6 ","Use ping6 rather than ping"){ @inet6 = "6"}
79
- argParser.on("-n","--[no]-numeric ","No attempt will be made to lookup symbolic names for host addresses"){ @numeric = '-n' }
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 ping()
114
- @pingio = IO.popen("ping#{@inet6} #{@numeric} #{@count} #{@interval} #{@addr}")
124
+ def run()
125
+ @binio = IO.popen("#{@@bin}#{@inet6} #{@numeric} #{@count} #{@interval} #{@broadcast} #{@addr}")
115
126
  while true
116
- row = @pingio.readline
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 @pingio.nil?
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
- ping
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 @pingio.nil?
143
+ return if @binio.nil?
147
144
  # Kill the ping process, which will result in EOFError from ping()
148
- Process.kill("INT", @pingio.pid)
145
+ Process.kill("INT", @binio.pid)
149
146
  end
150
147
 
151
148
  end #end of class
152
149
 
153
150
  begin
154
- $stderr.puts " INFO ping-oml2: V#{OML4R::VERSION}\n"
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
- $stderr.puts " ERROR ping-oml2: #{ex}\n"
176
+ OML4R.logger.error "#{@@appname}: #{ex}"
163
177
  end
164
178
 
165
179
  # Local Variables:
@@ -63,7 +63,7 @@ begin
63
63
  op.on("--oml-ch2 URL", "Set destination for Channel 2 [#{ch2.url}]") { |url| ch2.url = url }
64
64
  end
65
65
  rescue OML4R::MissingArgumentException => mex
66
- $stderr.puts mex
66
+ OML4R.logger.error "oml4r-multiple-channel-example: #{mex}"
67
67
  exit
68
68
  end
69
69
 
@@ -48,7 +48,7 @@ opts = {:appName => 'oml4rSimpleExample',
48
48
  begin
49
49
  OML4R::init(ARGV, opts)
50
50
  rescue OML4R::MissingArgumentException => mex
51
- $stderr.puts mex
51
+ OML4R.logger.error "oml4r-simple-example: #{mex}"
52
52
  exit
53
53
  end
54
54
 
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") { noop = true }
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; exit }
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
- OML4R.logger.debug "ARGV: #{argv.inspect}"
404
- return if noop
405
- # Parameters in OML config file takes precedence
406
- unless omlConfigFile.nil?
407
- f = File.open(omlConfigFile, 'r')
408
- f.each_line do |l|
409
- d = l[/.*experiment=["']([^"']*)/,1]
410
- opts[:domain] = d if d
411
- d = l[/.*domain=["']([^"']*)/,1]
412
- opts[:domain] = d if d
413
- i = l[/.*id=["']([^"']*)/,1]
414
- opts[:nodeID] = i if i
415
- u = l[/.*url=["']([^"']*)/,1]
416
- opts[:omlCollectUri] = u if u
417
- end
418
- f.close
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
- unless opts[:nodeID]
426
+ unless opts[:nodeID]
423
427
  begin
424
- # Create a default nodeID by concatinating the local hostname with the process ID
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
- unless opts[:domain] && opts[:appName]
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
- VERSION = "2.10.4"
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 ship with the oml4r gem. To use it, copy the application definition file into the ame directory as your OEDL experiment and run the EC from there.
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 = ["oml-user@lists.nicta.com.au"]
9
- gem.description = ["Simple OML client library and applications for Ruby"]
10
- gem.summary = ["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."]
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-03-03 00:00:00.000000000 Z
12
+ date: 2014-09-22 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: ! '["Simple OML client library and applications for Ruby"]'
15
- email:
16
- - oml-user@lists.nicta.com.au
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/ping-oml2.app.rb
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: '0'
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: ! '["This is a simple client library for OML which does not use liboml2 and
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: