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 +15 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +57 -0
- data/Rakefile +1 -0
- data/config/rc.yml.sample +16 -0
- data/config/test.rb +54 -0
- data/lib/omf_rc/resource_proxy/scheduled_application.rb +522 -0
- data/lib/omf_rc/resource_proxy/shm_node.rb +27 -0
- data/lib/omf_rc_shm/app/definition.rb +138 -0
- data/lib/omf_rc_shm/app/dsl.rb +13 -0
- data/lib/omf_rc_shm/app.rb +21 -0
- data/lib/omf_rc_shm/version.rb +3 -0
- data/lib/omf_rc_shm.rb +12 -0
- data/omf_rc_shm.gemspec +25 -0
- data/test/scheduled_app_controller.rb +15 -0
- data/test/scheduled_app_tester.rb +59 -0
- metadata +133 -0
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
data/Gemfile
ADDED
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
|
data/lib/omf_rc_shm.rb
ADDED
data/omf_rc_shm.gemspec
ADDED
@@ -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
|