omf_rc_shm 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OTM4MTc2MWI2YzI4ZTQ1NTVhYjJkNmY1ZWRjOWM2MWNkMTJhNmI5Yg==
5
+ data.tar.gz: !binary |-
6
+ MWNiMDIzYWEzZDlmMmU2M2UzYTZlMjYwZjZjZjkxZGFiN2FmNDk4NQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ODNkZWU1YWEwYzk0NTIxMTJiMjFmZTg0NDY5Y2M0MWM0Mjk0N2U0NWVkOWM3
10
+ MDYxNmRhNTFkYmZkYmJlYzljM2RjZTQyODk2NWJhYmNhZjJlZGJlZDQ5MmFm
11
+ OWQ5MThkNGZlNWFhNzNkNjc4ODZhNjllNmFkODU3OTI3YWM1ZjE=
12
+ data.tar.gz: !binary |-
13
+ NGVmNjY1ZTcxOTkzMzE1ZWJmZjAxZDgxNzg3YWUyNzljOWM5MDM2YTY2YTVl
14
+ MjA2YmRiMjQ1NDlhNTEyYjMyNTcxNzIzM2Y4ZGQyMzQzN2VjZTFlYTRjNzEx
15
+ NjFlMDZjNDIwNWRiMmRkZjU3ODhiNWRiMWQwYTgxNGI0ZTA5ZjQ=
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ **/*tags
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in omf_rc_shm.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jack C Hong
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # OmfRcShm
2
+
3
+ An extension to OmfRc provides support for structure health monitoring project
4
+
5
+ ## Installation
6
+
7
+ Install it as:
8
+
9
+ $ gem install omf_rc_shm
10
+
11
+ Setup startup script
12
+
13
+ $ install_omf_rc -c -i
14
+
15
+ Configure OmfRc to load SHM extension, simply modify '/etc/omf_rc/config.yml' to something like this:
16
+
17
+ ---
18
+ :uri: xmpp://<%= "#{Socket.gethostname}-#{Process.pid}" %>:<%= "#{Socket.gethostname}-#{Process.pid}" %>@srv.mytestbed.net
19
+ :environment: production
20
+
21
+ :resources:
22
+ - :type: shm_node
23
+ :uid: <%= Socket.gethostname %>
24
+ :app_definition_file: <path_to_app_definition_file>
25
+ :add_default_factories: false
26
+ :factories:
27
+ - :require: omf_rc_shm
28
+
29
+ Where app_definition_file for shm_node simply defines the applications it runs using OEDL defApplication syntax.
30
+
31
+ Example of defApplication:
32
+
33
+ defApplication('otr2') do |a|
34
+ a.schedule = "* 18 * * *"
35
+ a.binary_path = "/usr/bin/otr2"
36
+ a.defProperty('udp_local_host', 'IP address of this Destination node', '--udp:local_host', { :type => :string, :dynamic => false })
37
+ a.defProperty('udp_local_port', 'Receiving Port of this Destination node', '--udp:local_port', { :type => :integer, :dynamic => false })
38
+ a.defMeasurement('udp_in') do |m|
39
+ m.defMetric('flow_id',:long)
40
+ m.defMetric('seq_no',:long)
41
+ m.defMetric('pkt_length',:long)
42
+ m.defMetric('dst_host',:string)
43
+ m.defMetric('dst_port',:long)
44
+ end
45
+ end
46
+
47
+ ## Usage
48
+
49
+ OmfRc with SHM extension should start up automatically during boot.
50
+
51
+ ## Contributing
52
+
53
+ 1. Fork it
54
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
55
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
56
+ 4. Push to the branch (`git push origin my-new-feature`)
57
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,16 @@
1
+ # Use this with standard omf_rc
2
+ ---
3
+ :uri: local://local
4
+ :environment: development
5
+ :debug: false
6
+
7
+ :resources:
8
+ - :type: shm_node
9
+ :uid: <%= Socket.gethostname %>
10
+ :app_definition_file: path_to_your_app_definition_file
11
+
12
+ :add_default_factories: false # Not loading default type factories
13
+
14
+ :factories: # Additional resources which can be created by this RC
15
+ - :require: omf_rc_shm
16
+
data/config/test.rb ADDED
@@ -0,0 +1,54 @@
1
+ defApplication('otr2') do |a|
2
+ a.schedule = "* * * * *"
3
+ a.timeout = 20
4
+ a.binary_path = "/usr/bin/otr2"
5
+ a.description = <<TEXT
6
+ otr is a configurable traffic sink. It contains port to receive
7
+ packet streams via various transport options, such as TCP and UDP.
8
+ This version 2 is compatible with OMLv2.
9
+ TEXT
10
+
11
+ a.defProperty('udp_local_host', 'IP address of this Destination node', '--udp:local_host', {:type => :string, :dynamic => false})
12
+ a.defProperty('udp_local_port', 'Receiving Port of this Destination node', '--udp:local_port', {:type => :integer, :dynamic => false})
13
+ a.defMeasurement('udp_in') do |m|
14
+ m.defMetric('flow_id',:long)
15
+ m.defMetric('seq_no',:long)
16
+ m.defMetric('pkt_length',:long)
17
+ m.defMetric('dst_host',:string)
18
+ m.defMetric('dst_port',:long)
19
+ end
20
+ end
21
+
22
+ defApplication('otg2') do |a|
23
+ a.schedule = "* * * * *"
24
+ a.timeout = 20
25
+ a.binary_path = "/usr/bin/otg2"
26
+ a.description = <<TEXT
27
+ OTG is a configurable traffic generator. It contains generators
28
+ producing various forms of packet streams and port for sending
29
+ these packets via various transports, such as TCP and UDP.
30
+ This version 2 is compatible with OMLv2
31
+ TEXT
32
+
33
+ a.defProperty('generator', 'Type of packet generator to use (cbr or expo)', '-g', {:type => :string, :dynamic => false})
34
+ a.defProperty('udp_broadcast', 'Broadcast', '--udp:broadcast', {:type => :integer, :dynamic => false})
35
+ a.defProperty('udp_dst_host', 'IP address of the Destination', '--udp:dst_host', {:type => :string, :dynamic => false})
36
+ a.defProperty('udp_dst_port', 'Destination Port to send to', '--udp:dst_port', {:type => :integer, :dynamic => false})
37
+ a.defProperty('udp_local_host', 'IP address of this Source node', '--udp:local_host', {:type => :string, :dynamic => false})
38
+ a.defProperty('udp_local_port', 'Local Port of this source node', '--udp:local_port', {:type => :integer, :dynamic => false})
39
+ a.defProperty("cbr_size", "Size of packet [bytes]", '--cbr:size', {:dynamic => true, :type => :integer})
40
+ a.defProperty("cbr_rate", "Data rate of the flow [kbps]", '--cbr:rate', {:dynamic => true, :type => :integer})
41
+ a.defProperty("exp_size", "Size of packet [bytes]", '--exp:size', {:dynamic => true, :type => :integer})
42
+ a.defProperty("exp_rate", "Data rate of the flow [kbps]", '--exp:rate', {:dynamic => true, :type => :integer})
43
+ a.defProperty("exp_ontime", "Average length of burst [msec]", '--exp:ontime', {:dynamic => true, :type => :integer})
44
+ a.defProperty("exp_offtime", "Average length of idle time [msec]", '--exp:offtime', {:dynamic => true, :type => :integer})
45
+ a.defMeasurement('udp_out') do |m|
46
+ m.defMetric('ts',:float)
47
+ m.defMetric('flow_id',:long)
48
+ m.defMetric('seq_no',:long)
49
+ m.defMetric('pkt_length',:long)
50
+ m.defMetric('dst_host',:string)
51
+ m.defMetric('dst_port',:long)
52
+ end
53
+ end
54
+
@@ -0,0 +1,522 @@
1
+ # Copyright (c) 2013 National ICT Australia Limited (NICTA).
2
+ # This software may be used and distributed solely under the terms of the MIT license (License).
3
+ # You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
4
+ # By downloading or using this software you accept the terms and the liability disclaimer in the License.
5
+
6
+ # This module defines a Resource Proxy (RP) for an Application.
7
+ # For a detailed usage tutorial see {file:doc/RESOURCE\_PROXY.mkd Resource Proxy tutorial}
8
+ #
9
+ # Utility dependencies: platform_toos, common_tools
10
+ #
11
+ # This Application Proxy has the following properties:
12
+ #
13
+ # - binary_path (String) the path to the binary of this app
14
+ # - state (String) the state of this Application RP
15
+ # (unscheduled, scheduled)
16
+ # - map_err_to_out (Boolean) if true then map StdErr to StdOut for this
17
+ # app (default false)
18
+ # - platform (Symbol) the OS platform where this app is scheduled
19
+ # - environment (Hash) the environment variables to set prior to starting
20
+ # this app. { k1 => v1, ... } will result in "env -i K1=v1 ... "
21
+ # (with k1 being either a String or a Symbol)
22
+ # - use_oml (Boolean) if true enable OML for this application (default false)
23
+ # - oml_loglevel (Integer) set a specific OML log level (default unset)
24
+ # - oml_logfile (String) set a specific path for OML log file (default unset)
25
+ # - oml_configfile (String) path of the OML config file (optional)
26
+ # - oml (Hash) OML specific properties (optional), this Hash contains the
27
+ # following keys:
28
+ # - :available_mps (Array) list of available OML Measurement Points (Hash)
29
+ # - :collection (Hash) list of required OML Measurement Stream to collect
30
+ # when this application is scheduled (defined in liboml2.conf manpage)
31
+ # http://omf.mytestbed.net/doc/oml/html/liboml2.conf.html
32
+ # - :experiment (String) name of the experiment in which this application
33
+ # is scheduled
34
+ # - :id (String) OML id to use for this application when it is scheduled
35
+ # - parameters (Hash) the command line parameters available for this app.
36
+ # This hash is of the form: { :param1 => attribut1, ... }
37
+ # with param1 being the id of this parameter for this Proxy and
38
+ # with attribut1 being another Hash with the following possible
39
+ # keys and values (all are optional):
40
+ # :cmd (String) the command line for this parameter
41
+ # :order (Fixnum) the appearance order on the command line, default FIFO
42
+ # :dynamic (Boolean) parameter can be dynammically changed, default false
43
+ # :type (Numeric|String|Boolean) this parameter's type
44
+ # :default value given by default to this parameter
45
+ # :value value to set for this parameter
46
+ # :mandatory (Boolean) this parameter is mandatory, default false
47
+ #
48
+ # Note: this application proxy will merge new Hash values for the properties
49
+ # environment, oml, and parameters properties with the old Hash values.
50
+ #
51
+ # Two examples of valid parameters definition are:
52
+ #
53
+ # { :host => {:default => 'localhost', :type => 'String',
54
+ # :mandatory => true, :order => 2},
55
+ # :port => {:default => 5000, :type => 'Numeric', :cmd => '-p',
56
+ # :mandatory => true, :order => 1},
57
+ # :size => {:default => 512, :type => 'Numeric', :cmd => '--pkt-size',
58
+ # :mandatory => true, :dynamic => true}
59
+ # :title => {:type => 'String', :mandatory => false}
60
+ # }
61
+ #
62
+ # and
63
+ #
64
+ # { :title => {:value => "My First Application"} }
65
+ #
66
+
67
+ require 'cronedit'
68
+ require 'listen'
69
+
70
+ module OmfRc::ResourceProxy::ScheduledApplication
71
+ include OmfRc::ResourceProxyDSL
72
+ # @!macro extend_dsl
73
+
74
+ require 'omf_common/exec_app'
75
+
76
+ register_proxy :scheduled_application
77
+ # @!parse include OmfRc::Util::PlatformTools
78
+ # @!parse include OmfRc::Util::CommonTools
79
+ utility :platform_tools
80
+ utility :common_tools
81
+
82
+ MAX_PARAMETER_NUMBER = 1000
83
+ DEFAULT_MANDATORY_PARAMETER = false
84
+
85
+ property :app_id, :default => nil
86
+ property :description, :default => ''
87
+ property :binary_path, :default => nil
88
+ property :platform, :default => nil
89
+ property :state, :default => :unscheduled
90
+ property :map_err_to_out, :default => false
91
+ property :event_sequence, :default => 0
92
+ property :parameters, :default => Hashie::Mash.new
93
+ property :environments, :default => Hashie::Mash.new
94
+ property :use_oml, :default => false
95
+ property :oml_configfile, :default => nil
96
+ property :oml, :default => Hashie::Mash.new
97
+ property :oml_logfile, :default => nil
98
+ property :oml_loglevel, :default => nil
99
+ property :schedule, :default => nil
100
+ property :timeout, :default => 0
101
+ property :timeout_kill_signal, :default => 'TERM'
102
+ property :file_change_listener, :default => nil
103
+ property :file_change_callback, :default => nil
104
+ property :file_read_offset, :default => {}
105
+ property :app_log_dir, :default => '/tmp/omf_scheduled_app'
106
+
107
+ # @!macro group_hook
108
+ #
109
+ # hook :before_ready do |res|
110
+ # define_method("on_app_event") { |*args| process_event(self, *args) }
111
+ # end
112
+
113
+ hook :before_release do |app|
114
+ app.configure_state(:unscheduled)
115
+ end
116
+
117
+ # @!macro hook
118
+ # @!method after_initial_configured
119
+ hook :after_initial_configured do |res|
120
+ # if state was set to scheduled from the create we need
121
+ # to make sure that this happens!
122
+ if res.property.state.to_s.downcase.to_sym == :scheduled
123
+ res.property.state = :unscheduled
124
+ res.switch_to_scheduled
125
+ end
126
+ end
127
+
128
+ # @!endgroup
129
+
130
+ # This method processes an event coming from the application instance, which
131
+ # was started by this Resource Proxy (RP). It is a callback, which is usually
132
+ # called by the ExecApp class in OMF
133
+ #
134
+ # @param [AbstractResource] res this RP
135
+ # @param [String] event_type the type of event from the app instance
136
+ # (STARTED, EXIT, STDOUT, STDERR)
137
+ # @param [String] app_id the id of the app instance
138
+ # @param [String] msg the message carried by the event
139
+ def process_event(res, event_type, app_id, msg)
140
+ logger.info "App Event from '#{app_id}' "+
141
+ "(##{res.property.event_sequence}) - "+
142
+ "#{event_type}: '#{msg}'"
143
+ res.property.event_sequence += 1
144
+ if event_type == 'EXIT'
145
+ res.property.state = :unscheduled
146
+ res.inform(:status, {
147
+ status_type: 'APP_EVENT',
148
+ event: event_type.to_s.upcase,
149
+ app: app_id,
150
+ exit_code: msg,
151
+ msg: msg,
152
+ state: res.property.state,
153
+ seq: res.property.event_sequence,
154
+ uid: res.uid # do we really need this? Should be identical to 'src'
155
+ }, :ALL)
156
+ else
157
+ res.inform(:status, {
158
+ status_type: 'APP_EVENT',
159
+ event: event_type.to_s.upcase,
160
+ app: app_id,
161
+ msg: msg,
162
+ seq: res.property.event_sequence,
163
+ uid: res.uid
164
+ }, :ALL)
165
+ end
166
+ end
167
+
168
+ # @!macro group_request
169
+ #
170
+ # Request the platform property of this Application RP
171
+ # @see OmfRc::ResourceProxy::Application
172
+ #
173
+ # @!macro request
174
+ # @!method request_platform
175
+ request :platform do |res|
176
+ res.property.platform = detect_platform if res.property.platform.nil?
177
+ res.property.platform.to_s
178
+ end
179
+
180
+ # @!endgroup
181
+ # @!macro group_configure
182
+
183
+ # Configure the environments and oml property of this Application RP
184
+ # @see OmfRc::ResourceProxy::Application
185
+ #
186
+ #
187
+ # @!macro configure
188
+ # @!method conifgure_environments
189
+ # @!method conifgure_oml
190
+ %w(environments oml).each do |prop|
191
+ configure(prop) do |res, value|
192
+ if value.kind_of? Hash
193
+ res.property[prop] = res.property[prop].merge(value)
194
+ else
195
+ res.log_inform_error "Configuration failed for '#{prop}'! "+
196
+ "Value not passed as Hash (#{value.inspect})"
197
+ end
198
+ res.property[prop]
199
+ end
200
+ end
201
+
202
+ # Configure the parameters property of this Application RP
203
+ #
204
+ # @!macro configure
205
+ # @see OmfRc::ResourceProxy::Application
206
+ # @!method configure_parameters
207
+ #
208
+ configure :parameters do |res, params|
209
+ if params.kind_of? Hash
210
+ params.each do |p,v|
211
+ if v.kind_of? Hash
212
+ # if this param has no set order, then assign the highest number to it
213
+ # this will allow sorting the parameters later
214
+ v[:order] = MAX_PARAMETER_NUMBER if v[:order].nil?
215
+ # if this param has no set mandatory field, assign it a default one
216
+ v[:mandatory] = DEFAULT_MANDATORY_PARAMETER if v[:mandatory].nil?
217
+ new_val = res.property.parameters[p].nil? ? v : res.property.parameters[p].merge(v)
218
+ # only set this new parameter if it passes the type check
219
+ if res.pass_type_checking?(new_val)
220
+ res.property.parameters[p] = new_val
221
+ #res.dynamic_parameter_update(p,new_val)
222
+ else
223
+ res.log_inform_error "Configuration of parameter '#{p}' failed "+
224
+ "type checking. Defined type is #{new_val[:type]} while assigned "+
225
+ "value/default are #{new_val[:value].inspect} / "+
226
+ "#{new_val[:default].inspect}"
227
+ end
228
+ else
229
+ res.log_inform_error "Configuration of parameter '#{p}' failed!"+
230
+ "Options not passed as Hash (#{v.inspect})"
231
+ end
232
+ end
233
+ else
234
+ res.log_inform_error "Parameter configuration failed! Parameters not "+
235
+ "passed as Hash (#{params.inspect})"
236
+ end
237
+ res.property.parameters
238
+ end
239
+
240
+ # Configure the state of this Application RP. The valid states are
241
+ # unscheduled, scheduled, paused. The semantic of each states are:
242
+ #
243
+ # - unscheduled: the initial state for an Application RP
244
+ # - completed: the final state for an application RP. When the application
245
+ # has been executed and its execution is finished, it enters this state.
246
+ # When the application is completed it cannot change state again
247
+ # TODO: maybe in future OMF, we could consider allowing an app to be reset?
248
+ # - scheduled: upon entering in this state, a new instance of the application is
249
+ # started, the Application RP stays in this state until the
250
+ # application instance is finished or paused. The Application RP can
251
+ # only enter this state from a previous paused or unscheduled state.
252
+ # - paused: upon entering this state, the currently scheduled instance of this
253
+ # application should be paused (it is the responsibility of
254
+ # specialised Application Proxy to ensure that! This default
255
+ # Application Proxy does nothing to the application instance when
256
+ # entering this state). The Application RP can only enter this
257
+ # state from a previous scheduled state.
258
+ #
259
+ # @param [String] value the state to set this app into
260
+ # @!macro configure
261
+ # @!method configure_state
262
+ configure :state do |res, value|
263
+ OmfCommon.eventloop.after(0) do
264
+ case value.to_s.downcase.to_sym
265
+ when :unscheduled then res.switch_to_unscheduled
266
+ when :scheduled then res.switch_to_scheduled
267
+ else
268
+ res.log_inform_warn "Cannot switch application to unknown state '#{value.to_s}'!"
269
+ end
270
+ end
271
+ res.property.state
272
+ end
273
+
274
+ # @!endgroup
275
+
276
+ # @!macro group_work
277
+
278
+ # Switch this Application RP into the 'unscheduled' state
279
+ # (see the description of configure :state)
280
+ #
281
+ # @!macro work
282
+ # @!method switch_to_unscheduled
283
+ work('switch_to_unscheduled') do |res|
284
+ if res.property.state == :scheduled
285
+ info "Removing cron job for #{res.property.app_id} with command #{res.build_command_line}"
286
+ CronEdit::Crontab.Remove res.property.app_id
287
+ res.property.file_change_listener.stop
288
+ res.property.state = :unscheduled
289
+ end
290
+ end
291
+
292
+ # Switch this Application RP into the 'scheduled' state
293
+ # (see the description of configure :state)
294
+ #
295
+ # @!macro work
296
+ # @!method switch_to_scheduled
297
+ work('switch_to_scheduled') do |res|
298
+ if res.property.state == :unscheduled
299
+ # start a new instance of this app
300
+ res.property.app_id = res.hrn.nil? ? res.uid : res.hrn
301
+ # we need at least a defined binary path to run an app...
302
+ if res.property.binary_path.nil?
303
+ res.log_inform_warn "Binary path not set! No Application to run!"
304
+ elsif res.property.schedule.nil?
305
+ res.log_inform_warn "No schedule given!"
306
+ else
307
+ Dir.mkdir(res.property.app_log_dir) if !Dir.exist?(res.property.app_log_dir)
308
+ stderr_file = "#{res.property.app_log_dir}/#{res.property.app_id}.err.log"
309
+ stdout_file = "#{res.property.app_log_dir}/#{res.property.app_id}.out.log"
310
+ File.delete(stderr_file) if File.exist?(stderr_file)
311
+ File.delete(stdout_file) if File.exist?(stdout_file)
312
+ cmd = "#{res.build_command_line} 2>>#{stderr_file} 1>>#{stdout_file} ; echo \"Application '#{res.property.app_id}' exited with code $? \" >>#{stderr_file}"
313
+ if res.property.timeout > 0
314
+ cmd = "timeout -s #{res.property.timeout_kill_signal} #{res.property.timeout} #{cmd}"
315
+ end
316
+ info "Adding cron job for '#{res.property.app_id}' with schedule '#{res.property.schedule}' and command '#{cmd}'"
317
+ CronEdit::Crontab.Add res.property.app_id, "#{res.property.schedule} #{cmd}"
318
+ # ExecApp.new(res.property.app_id,
319
+ # res.build_command_line,
320
+ # res.property.map_err_to_out) do |event_type, app_id, msg|
321
+ # res.process_event(res, event_type, app_id, msg)
322
+ # end
323
+ res.property.file_change_callback = Proc.new do |modified, added, removed|
324
+ removed.each do |file|
325
+ res.property.file_read_offset[file]=nil
326
+ end
327
+ files = added + modified
328
+ files.each do |file|
329
+ if file.include? stderr_file or file.include? stdout_file
330
+ res.property.file_read_offset[file]=0 if res.property.file_read_offset[file].nil?
331
+ p res.property.file_read_offset[file]
332
+ data = IO.read(file,nil,res.property.file_read_offset[file])
333
+ res.property.file_read_offset[file]+=data.length
334
+ data.split(/\r?\n/).each do |line|
335
+ event_type = (file.include? ".err.log") ? "STDERR" : "STDOUT"
336
+ res.process_event(res, event_type, res.property.app_id, line)
337
+ end
338
+ end
339
+ end
340
+ end
341
+ res.property.file_change_listener = Listen.to(res.property.app_log_dir).change(&res.property.file_change_callback)
342
+ res.property.file_change_listener.start
343
+ res.property.state = :scheduled
344
+ end
345
+ else
346
+ res.log_inform_warn "Cannot switch to scheduled state as current state is '#{res.property.state}'"
347
+ end
348
+ end
349
+
350
+ # Check if a configured value or default for a parameter has the same
351
+ # type as the type defined for that parameter
352
+ # The checking procedure is as follows:
353
+ # - first check if a type was set for this parameter, if not then return true
354
+ # (thus if no type was defined for this parameter then return true
355
+ # regardless of the type of the given value or default)
356
+ # - second check if a value is given, if so check if it has the same type as
357
+ # the defined type, if so then return true, if not then return false.
358
+ # - third if no value is given but a default is given, then perform the same
359
+ # check as above but using the default in-place of the value
360
+ #
361
+ # @param [Hash] att the Hash holding the parameter's attributs
362
+ #
363
+ # @return [Boolean] true or false
364
+ # @!macro work
365
+ work('pass_type_checking?') do |res,att|
366
+ passed = false
367
+ unless att[:type].nil?
368
+ if att[:type] == 'Boolean' # HACK: as Ruby does not have a Boolean type
369
+ if !att[:default].nil? && !att[:value].nil?
370
+ passed = true if res.boolean?(att[:default]) && res.boolean?(att[:value])
371
+ elsif att[:default].nil? && att[:value].nil?
372
+ passed = true
373
+ elsif att[:default].nil?
374
+ passed = true if res.boolean?(att[:value])
375
+ elsif att[:value].nil?
376
+ passed = true if res.boolean?(att[:default])
377
+ end
378
+ else # Now for all other types...
379
+ klass = Module.const_get(att[:type].capitalize.to_sym)
380
+ if !att[:default].nil? && !att[:value].nil?
381
+ passed = true if att[:default].kind_of?(klass) && att[:value].kind_of?(klass)
382
+ elsif att[:default].nil? && att[:value].nil?
383
+ passed = true
384
+ elsif att[:default].nil?
385
+ passed = true if att[:value].kind_of?(klass)
386
+ elsif att[:value].nil?
387
+ passed = true if att[:default].kind_of?(klass)
388
+ end
389
+ end
390
+ else
391
+ passed = true
392
+ end
393
+ passed
394
+ end
395
+
396
+ # Build the command line, which will be used to start this app.
397
+ #
398
+ # This command line will be of the form:
399
+ # "env -i VAR1=value1 ... application_path parameterA valueA ..."
400
+ #
401
+ # The environment variables and the parameters in that command line are
402
+ # taken respectively from the 'environments' and 'parameters' properties of
403
+ # this Application Resource Proxy. If the 'use_oml' property is set, then
404
+ # add to the command line the necessary oml parameters.
405
+ #
406
+ # @return [String] the full command line
407
+ # @!macro work
408
+ work('build_command_line') do |res|
409
+ cmd_line = "env -i " # Start with a 'clean' environment
410
+ res.property.environments.each do |e,v|
411
+ val = v.kind_of?(String) ? "'#{v}'" : v
412
+ cmd_line += "#{e.to_s.upcase}=#{val} "
413
+ end
414
+ cmd_line += res.property.binary_path + " "
415
+ # Add command line parameter in their specified order if any
416
+ sorted_parameters = res.property.parameters.sort_by {|k,v| v[:order] || -1}
417
+ sorted_parameters.each do |param,att|
418
+ needed = false
419
+ needed = att[:mandatory] if res.boolean?(att[:mandatory])
420
+ # For mandatory parameter without a value, take the default one
421
+ val = (needed && att[:value].nil?) ? att[:default] : att[:value]
422
+ # Finally add the parameter if is value/default is not nil
423
+ unless val.nil?
424
+ if att[:type] == "Boolean"
425
+ # for Boolean param, only the command is printed if value==true
426
+ cmd_line += "#{att[:cmd]} " if val == true
427
+ else
428
+ # for all other type of param, we print "cmd value"
429
+ # with a user-provided prefix/suffix if defined
430
+ cmd_line += "#{att[:cmd]} "
431
+ cmd_line += att[:prefix].nil? ? "#{val}" : "#{att[:prefix]}#{val}"
432
+ cmd_line += att[:suffix].nil? ? " " : "#{att[:suffix]} "
433
+ end
434
+ end
435
+ end
436
+ # Add OML parameters if required
437
+ cmd_line = res.build_oml_config(cmd_line) if res.property.use_oml
438
+ cmd_line
439
+ end
440
+
441
+ # Add the required OML parameter to the command line for this application
442
+ #
443
+ # - if the 'oml_configfile' property is set with a filename, then we use that
444
+ # file as the OML Configuration file. Thus we add the parameter
445
+ # "--oml-config filename" to this application's command line
446
+ # - if the 'oml' property is set with a Hash holding an OML configuration,
447
+ # then we write turn it into OML's XML configuration representation, write
448
+ # it to a temporary file, and add the parameter "--oml-config tmpfile" to
449
+ # this application's command line. The OML configuration hash is based
450
+ # on the liboml2.conf man page, an example of which is:
451
+ # <omlc domain="my_experiment" id="my_source_id">
452
+ # <collect url="tcp://10.0.0.200">
453
+ # <stream mp="radiotap" interval="2">
454
+ # <filter field="sig_strength_dBm" />
455
+ # <filter field="noise_strength_dBm" />
456
+ # <filter field="power" />
457
+ # </stream>
458
+ # <stream mp="udp" samples="10">
459
+ # <filter field="udp_len" />
460
+ # </stream>
461
+ # </collect>
462
+ # </omlc>
463
+ #
464
+ # The 'oml_configfile' case takes precedence over the 'oml' case above.
465
+ #
466
+ # Regardless of which case is performed, we will always set the
467
+ # '--oml-log-level' and '--oml-log-file' parameter on the command line if
468
+ # the corresponsding 'oml_logfile' and 'oml_loglevel' properties are set for
469
+ # this application resource.
470
+ #
471
+ # @param [String] cmd the String to which OML parameters will be added
472
+ #
473
+ # @return [String] the resulting command line
474
+ # @!macro work
475
+ work('build_oml_config') do |res, cmd|
476
+ if !res.property.oml_configfile.nil?
477
+ if File.exist?(res.property.oml_configfile)
478
+ cmd += "--oml-config #{res.property.oml_configfile} "
479
+ else
480
+ res.log_inform_warn "OML enabled but OML config file does not exist"+
481
+ "(file: '#{res.property.oml_configfile}')"
482
+ end
483
+ elsif !res.property.oml.collection.nil?
484
+ o = res.property.oml
485
+ ofile = "/tmp/#{res.uid}-#{Time.now.to_i}.xml"
486
+ of = File.open(ofile,'w')
487
+ of << "<omlc experiment='#{o.experiment}' id='#{o.id}'>\n"
488
+ o.collection.each do |c|
489
+ of << " <collect url='#{c.url}'>\n"
490
+ c.streams.each do |m|
491
+ # samples as precedence over interval
492
+ s = ''
493
+ s = "interval='#{m.interval}'" if m.interval
494
+ s = "samples='#{m.samples}'" if m.samples
495
+ of << " <stream mp='#{m.mp}' #{s}>\n"
496
+ unless m.filters.nil?
497
+ m.filters.each do |f|
498
+ line = " <filter field='#{f.field}' "
499
+ line += "operation='#{f.operation}' " unless f.operation.nil?
500
+ line += "rename='#{f.rename}' " unless f.rename.nil?
501
+ line += "/>\n"
502
+ of << line
503
+ end
504
+ end
505
+ of << " </stream>\n"
506
+ end
507
+ of << " </collect>\n"
508
+ end
509
+ of << "</omlc>\n"
510
+ of.close
511
+ cmd += "--oml-config #{ofile}"
512
+ else
513
+ res.log_inform_warn "OML enabled but no OML configuration was given"+
514
+ "(file: '#{res.property.oml_configfile}' - "+
515
+ "config: '#{res.property.oml.inspect}')"
516
+ end
517
+ cmd += "--oml-log-level #{res.property.oml_loglevel} " unless res.property.oml_loglevel.nil?
518
+ cmd += "--oml-log-file #{res.property.oml_logfile} " unless res.property.oml_logfile.nil?
519
+ cmd
520
+ end
521
+
522
+ end
@@ -0,0 +1,27 @@
1
+ module OmfRc::ResourceProxy::ShmNode
2
+ include OmfRc::ResourceProxyDSL
3
+
4
+ register_proxy :shm_node
5
+
6
+ property :app_definition_file
7
+
8
+ request :cron_jobs do |node|
9
+ node.children.find_all { |v| v.type =~ /scheduled_application/ }.map do |v|
10
+ { name: v.hrn, type: v.type, uid: v.uid }
11
+ end.sort { |x, y| x[:name] <=> y[:name] }
12
+ end
13
+
14
+ hook :after_initial_configured do |node|
15
+ OmfRcShm.app.load_definition(node.request_app_definition_file)
16
+
17
+ OmfRcShm.app.definitions.each do |d|
18
+ info "Got definition #{d.inspect}, now schedule them..."
19
+ app_id = d[0]
20
+ app_opts = d[1].properties.merge(hrn: app_id, use_oml: true)
21
+ s_app = OmfRc::ResourceFactory.create(:scheduled_application, app_opts)
22
+ OmfCommon.el.after(5) do
23
+ s_app.configure_state(:scheduled)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,138 @@
1
+ require 'securerandom'
2
+
3
+ module OmfRcShm
4
+ class App
5
+ # Application Definition used in experiment script
6
+ #
7
+ # @!attribute name [String] name of the resource
8
+ class Definition
9
+
10
+ # TODO: eventually this call would mirror all the properties of the App Proxy
11
+ # right now we just have name, binary_path, parameters
12
+ attr_accessor :name, :properties
13
+
14
+ # @param [String] name name of the application to define
15
+ def initialize(name)
16
+ self.name = name
17
+ self.properties = Hashie::Mash.new
18
+ end
19
+
20
+ # Add new parameter(s) to this Application Definition
21
+ #
22
+ # @param [Hash] params a hash with the parameters to add
23
+ #
24
+ def define_parameter(params)
25
+ @properties[:parameters] = Hashie::Mash.new unless @properties.key?(:parameters)
26
+ if params.kind_of? Hash
27
+ @properties[:parameters].merge!(params)
28
+ else
29
+ error "Cannot define parameter for app '#{self.name}'! Parameter "+
30
+ "not passed as a Hash ('#{params.inspect}')"
31
+ end
32
+ end
33
+
34
+ def define_measurement_point(mp)
35
+ @properties[:oml] = Hashie::Mash.new unless @properties.key?(:oml)
36
+ if mp.kind_of? Hash
37
+ @properties[:oml][:available_mps] = Array.new unless @properties[:oml].key?(:available_mps)
38
+ @properties[:oml][:available_mps] << mp
39
+ else
40
+ error "Cannot define Measurement Point for app '#{self.name}'! MP "+
41
+ "not passed as a Hash ('#{mp.inspect}')"
42
+ end
43
+ end
44
+
45
+ warn_removed :version
46
+
47
+ def path=(arg)
48
+ @properties[:binary_path] = arg
49
+ warn_deprecation :path=, :binary_path=
50
+ end
51
+
52
+ def shortDescription=(arg)
53
+ @properties[:description] = arg
54
+ warn_deprecation :shortDescription=, :description=
55
+ end
56
+
57
+ def method_missing(method_name, *args)
58
+ k = method_name.to_sym
59
+ return @properties[k] if @properties.key?(k)
60
+ m = method_name.to_s.match(/(.*?)([=]?)$/)
61
+ if m[2] == '='
62
+ @properties[m[1].to_sym] = args.first
63
+ else
64
+ super
65
+ end
66
+ end
67
+
68
+ # The following are OEDL 5 methods
69
+
70
+ # Add a new parameter to this Application Definition.
71
+ # This method is for backward compatibility with previous OEDL 5.
72
+ #
73
+ # @param [String] name name of the property to define (mandatory)
74
+ # @param [String] description description of this property; oml2-scaffold uses this for the help message (popt: descrip)
75
+ # @param [String] parameter command-line parameter to introduce this property, including dashes if needed (can be nil)
76
+ # @param [Hash] options list of options associated with this property
77
+ # @option options [String] :type type of the property: :integer, :string and :boolean are supported; oml2-scaffold extends this with :int and :double (popt: argInfo)
78
+ # @option options [Boolean] :dynamic true if the property can be changed at run-time
79
+ # @option options [Fixnum] :order used to order properties when creating the command line
80
+ #
81
+ # The OML code-generation tool, oml2-scaffold extends the range of
82
+ # options supported in the options hash to support generation of
83
+ # popt(3) command line parsing code. As for the parameters, depending
84
+ # on the number of dashes (two/one) in parameter, it is used as the
85
+ # longName/shortName for popt(3), otherwise the former defaults to
86
+ # name, and the latter defaults to either :mnemonic or nothing.
87
+ #
88
+ # @option options [String] :mnemonic one-letter mnemonic for the option (also returned by poptGetNextOpt as val)
89
+ # @option options [String] :unit unit in which this property is expressed; oml2-scaffold uses this for the help message (popt: argDescrip)
90
+ # @option options [String] :default default value if argument unspecified (optional; defaults to something sane for the :type)
91
+ # @option options [String] :var_name name of the C variable for popt(3) to store the property value into (optional; popt: arg; defaults to name, after sanitisation)
92
+ #
93
+ # @see http://oml.mytestbed.net/doc/oml/latest/oml2-scaffold.1.html
94
+ # @see http://linux.die.net/man/3/popt
95
+ #
96
+ def defProperty(name = :mandatory, description = nil, parameter = nil, options = {})
97
+ opts = {:description => description, :cmd => parameter}
98
+ # Map old OMF5 types to OMF6
99
+ options[:type] = 'Numeric' if options[:type] == :integer
100
+ options[:type] = 'String' if options[:type] == :string
101
+ options[:type] = 'Boolean' if options[:type] == :boolean
102
+ opts = opts.merge(options)
103
+ define_parameter(Hash[name,opts])
104
+ end
105
+
106
+ # Define metrics to measure
107
+ #
108
+ # @param [String] name of the metric
109
+ # @param [Symbol] type of the metric data. For all supporting metric data types, refers to http://oml.mytestbed.net/doc/oml/latest/oml2-scaffold.1.html#_mp_defmetric_name_type
110
+ # @param [Hash] opts additional options
111
+ #
112
+ # @option opts [String] :unit unit of measure of the metric
113
+ # @option opts [String] :description of the metric
114
+ # @option opts [Float] :precision precision of the metric value
115
+ # @option opts [Range] :range value range of the metric
116
+ #
117
+ # @example OEDL
118
+ # app.defMeasurement("power") do |mp|
119
+ # mp.defMetric('power', :double, :unit => "W", :precision => 0.1, :description => 'Power')
120
+ # end
121
+ def defMetric(name,type, opts = {})
122
+ # the third parameter used to be a description string
123
+ opts = {:description => opts} if opts.class!=Hash
124
+ @fields << {:field => name, :type => type}.merge(opts)
125
+ end
126
+
127
+ # XXX: This should be provided by the omf-oml glue.
128
+ def defMeasurement(name,&block)
129
+ mp = {:mp => name, :fields => []}
130
+ @fields = []
131
+ # call the block with ourserlves to process its 'defMetric' statements
132
+ block.call(self) if block
133
+ @fields.each { |f| mp[:fields] << f }
134
+ define_measurement_point(mp)
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,13 @@
1
+ module OmfRcShm
2
+ class App
3
+ module DSL
4
+ def defApplication(uri, name=nil ,&block)
5
+ name = uri if name.nil?
6
+ app_def = OmfRcShm::App::Definition.new(name)
7
+ OmfRcShm.app.definitions[name] = app_def
8
+ info "Adding new definition #{name}"
9
+ block.call(app_def) if block
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ require 'omf_rc_shm/app/dsl'
2
+ require 'omf_rc_shm/app/definition'
3
+ require 'singleton'
4
+
5
+ module OmfRcShm
6
+ class App
7
+ include Singleton
8
+ include OmfRcShm::App::DSL
9
+
10
+ attr_accessor :definitions
11
+
12
+ def initialize
13
+ super
14
+ @definitions ||= Hash.new
15
+ end
16
+
17
+ def load_definition(file_path)
18
+ eval(File.read(file_path))
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module OmfRcShm
2
+ VERSION = "0.0.1"
3
+ end
data/lib/omf_rc_shm.rb ADDED
@@ -0,0 +1,12 @@
1
+ require "omf_rc_shm/version"
2
+ require "omf_rc_shm/app"
3
+
4
+ require "omf_rc/resource_proxy/shm_node"
5
+ require "omf_rc/resource_proxy/scheduled_application"
6
+
7
+ module OmfRcShm
8
+ def self.app
9
+ OmfRcShm::App.instance
10
+ end
11
+ end
12
+
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'omf_rc_shm/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "omf_rc_shm"
8
+ spec.version = OmfRcShm::VERSION
9
+ spec.authors = ["NICTA"]
10
+ spec.email = ["omf-user@lists.nicta.com.au"]
11
+ spec.summary = "OMF resource proxy extension for SHM project"
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_runtime_dependency "omf_rc", "~> 6.0.5"
23
+ spec.add_runtime_dependency "cronedit"
24
+ spec.add_runtime_dependency "listen"
25
+ end
@@ -0,0 +1,15 @@
1
+ # Need omf_rc gem to be required
2
+ #
3
+ require 'omf_rc'
4
+ require 'omf_rc_shm'
5
+
6
+ # This init method will set up your run time environment,
7
+ # communication, eventloop, logging etc. We will explain that later.
8
+ #
9
+ OmfCommon.init(:development, communication: { url: 'xmpp://norbit.npc.nicta.com.au' }) do
10
+ OmfCommon.comm.on_connected do |comm|
11
+ info "Scheduled application controller >> Connected to XMPP server"
12
+ sched_app = OmfRc::ResourceFactory.create(:scheduled_application, uid: 'my_scheduled_app')
13
+ comm.on_interrupted { sched_app.disconnect }
14
+ end
15
+ end
@@ -0,0 +1,59 @@
1
+ # Use omf_common communicator directly
2
+ #
3
+ require 'omf_common'
4
+ $stdout.sync = true
5
+
6
+ def run_test(app)
7
+ # Set up inform message handler to print inform messages
8
+ app.on_inform do |m|
9
+ case m.itype
10
+ when 'STATUS'
11
+ if m[:status_type] == 'APP_EVENT'
12
+ info "APP_EVENT #{m[:event]} from app #{m[:app]} - msg: #{m[:msg]}"
13
+ end
14
+ when 'ERROR'
15
+ error m[:reason]
16
+ when 'WARN'
17
+ warn m[:reason]
18
+ end
19
+ end
20
+
21
+ # Configure the 'binary_path' and 'parameters' properties of the App Proxy
22
+ app.configure(binary_path: "date",
23
+ oml_configfile: "/Users/cdw/tempo/omf_rc_shm/README.md",
24
+ # use_oml: true,
25
+ schedule: "* * * * *")
26
+
27
+ # Start the application 2 seconds later
28
+ OmfCommon.eventloop.after 1 do
29
+ app.configure(state: :scheduled)
30
+ end
31
+
32
+ # Stop the application another 10 seconds later
33
+ OmfCommon.eventloop.after 120 do
34
+ app.configure(state: :unscheduled)
35
+ end
36
+ end
37
+ #
38
+ OmfCommon.init(:development, communication: { url: 'xmpp://norbit.npc.nicta.com.au' }) do
39
+ # Event :on_connected will be triggered when connected to XMPP server
40
+ #
41
+ OmfCommon.comm.on_connected do |comm|
42
+ info "Connected to XMPP"
43
+
44
+ comm.subscribe('my_scheduled_app') do |sched_app|
45
+ unless sched_app.error?
46
+ run_test(sched_app)
47
+ else
48
+ error sched_app.inspect
49
+ end
50
+ end
51
+
52
+ # Eventloop allows to control the flow, in this case, we disconnect after 5 seconds.
53
+ #
54
+ OmfCommon.eventloop.after(300) { comm.disconnect }
55
+ # If you hit ctrl-c, we will disconnect too.
56
+ #
57
+ comm.on_interrupted { comm.disconnect }
58
+ end
59
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omf_rc_shm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - NICTA
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: omf_rc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 6.0.5
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 6.0.5
55
+ - !ruby/object:Gem::Dependency
56
+ name: cronedit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: listen
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description:
84
+ email:
85
+ - omf-user@lists.nicta.com.au
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - Gemfile
92
+ - LICENSE.txt
93
+ - README.md
94
+ - Rakefile
95
+ - config/rc.yml.sample
96
+ - config/test.rb
97
+ - lib/omf_rc/resource_proxy/scheduled_application.rb
98
+ - lib/omf_rc/resource_proxy/shm_node.rb
99
+ - lib/omf_rc_shm.rb
100
+ - lib/omf_rc_shm/app.rb
101
+ - lib/omf_rc_shm/app/definition.rb
102
+ - lib/omf_rc_shm/app/dsl.rb
103
+ - lib/omf_rc_shm/version.rb
104
+ - omf_rc_shm.gemspec
105
+ - test/scheduled_app_controller.rb
106
+ - test/scheduled_app_tester.rb
107
+ homepage: ''
108
+ licenses:
109
+ - MIT
110
+ metadata: {}
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubyforge_project:
127
+ rubygems_version: 2.0.7
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: OMF resource proxy extension for SHM project
131
+ test_files:
132
+ - test/scheduled_app_controller.rb
133
+ - test/scheduled_app_tester.rb