omf_rc 6.0.0.pre.6 → 6.0.0.pre.7
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.
- data/bin/omf_rc +34 -26
- data/config/omf_rc.yml +10 -10
- data/lib/omf_rc/{message_process_error.rb → omf_error.rb} +8 -0
- data/lib/omf_rc/resource_factory.rb +4 -0
- data/lib/omf_rc/resource_proxy/abstract_resource.rb +107 -44
- data/lib/omf_rc/resource_proxy/{generic_application.rb → application.rb} +189 -142
- data/lib/omf_rc/resource_proxy/node.rb +33 -21
- data/lib/omf_rc/resource_proxy_dsl.rb +51 -9
- data/lib/omf_rc/util/iw.rb +10 -6
- data/lib/omf_rc/util/mod.rb +30 -2
- data/lib/omf_rc/util/openflow_tools.rb +8 -8
- data/lib/omf_rc/util/platform_tools.rb +13 -13
- data/lib/omf_rc/version.rb +1 -1
- data/test/fixture/iw/help +6 -6
- data/test/fixture/lsmod +56 -56
- data/test/fixture/oml.hash +30 -0
- data/test/fixture/oml.spec +15 -0
- data/test/fixture/oml.xml +17 -0
- data/test/omf_rc/resource_proxy/abstract_resource_spec.rb +4 -2
- data/test/omf_rc/resource_proxy/{generic_application_spec.rb → application_spec.rb} +73 -34
- data/test/omf_rc/resource_proxy/node_spec.rb +33 -17
- data/test/omf_rc/resource_proxy_dsl_spec.rb +7 -0
- data/test/omf_rc/util/common_tools_spec.rb +1 -1
- data/test/omf_rc/util/mod_spec.rb +9 -3
- metadata +8 -6
data/bin/omf_rc
CHANGED
@@ -10,42 +10,50 @@ options = {
|
|
10
10
|
}
|
11
11
|
|
12
12
|
executable_name = File.basename($PROGRAM_NAME)
|
13
|
+
oml_enabled = false
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
begin
|
16
|
+
oml_enabled = OML4R::init(ARGV, :appName => executable_name) do |opts|
|
17
|
+
opts.banner = "usage: #{executable_name} [options]"
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
opts.on("-u USER", "Username") do |user|
|
20
|
+
options[:user] = user
|
21
|
+
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
opts.on("-p PASSWORD", "Password") do |password|
|
24
|
+
options[:password] = password
|
25
|
+
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
opts.on("-s SERVER", "PubSub server") do |server|
|
28
|
+
options[:server] = server
|
29
|
+
end
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
opts.on("-t TOPIC", "PubSub topic to create, also becomes the uid of the resource, default to hostname") do |topic|
|
32
|
+
options[:uid] = topic
|
33
|
+
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
+
opts.on("-d", "--debug", "Debug mode") do
|
36
|
+
options[:debug] = true
|
37
|
+
end
|
35
38
|
end
|
36
|
-
end
|
37
|
-
|
38
|
-
begin
|
39
|
-
option_parser.parse!
|
40
39
|
rescue => e
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
# Right now OML4R does not raise proper exceptions :(
|
41
|
+
# OML4R requires --oml-noop to be set if we want to run without doing any
|
42
|
+
# measurements... this is too restrictive here, we want to run without OML
|
43
|
+
# if no OML parameters were set and this even if --oml-noop is not set.
|
44
|
+
if e.message.include?('OML4R: Missing values for parameters :expID ')
|
45
|
+
puts "Warning: Missing some OML options to instrument this RC, so it will "+
|
46
|
+
"run without instrumentation. (see --oml-help)"
|
47
|
+
else
|
48
|
+
puts e.message
|
49
|
+
exit(1)
|
50
|
+
end
|
45
51
|
end
|
46
52
|
|
47
|
-
|
48
|
-
|
53
|
+
OmfCommon::Measure.enable if oml_enabled
|
54
|
+
|
55
|
+
unless options[:server] && options[:user] && options[:password]
|
56
|
+
puts "Error: Missing parameters to connect to a PubSub Server (see --help)"
|
49
57
|
exit(1)
|
50
58
|
end
|
51
59
|
|
data/config/omf_rc.yml
CHANGED
@@ -5,35 +5,35 @@
|
|
5
5
|
#
|
6
6
|
---
|
7
7
|
:rcontroller:
|
8
|
-
# Communication settings
|
8
|
+
# Communication settings
|
9
9
|
:communicator:
|
10
|
-
|
11
|
-
# Interface to the control network from which this resource can be
|
10
|
+
|
11
|
+
# Interface to the control network from which this resource can be
|
12
12
|
# controlled & managed
|
13
13
|
:control_if: 'control'
|
14
14
|
|
15
|
-
# set this to true or false if you want to enable or disable signature checks and message signing
|
15
|
+
# set this to true or false if you want to enable or disable signature checks and message signing
|
16
16
|
:authenticate_messages: false
|
17
17
|
# your RSA/DSA SSH private key file
|
18
18
|
:private_key: '/etc/omf-resctl-5.4/id_rsa'
|
19
19
|
# directory holding the public keys of your OMF peers
|
20
20
|
:public_key_dir: '/etc/omf-resctl-5.4/peer_keys'
|
21
|
-
|
21
|
+
|
22
22
|
:type: 'xmpp'
|
23
23
|
:xmpp:
|
24
24
|
# Address of the PubSub server to use as gateway for PubSub communication
|
25
25
|
:pubsub_gateway: 'norbit.npc.nicta.com.au'
|
26
26
|
#:pubsub_port: 5222
|
27
27
|
# Address of the PubSub server which host the communication for my slice
|
28
|
-
# Leave this commented if the pubsub groups for this slice are hosted on
|
28
|
+
# Leave this commented if the pubsub groups for this slice are hosted on
|
29
29
|
# the same server as the 'pubsub_gateway'
|
30
30
|
#:pubsub_domain: 10.0.0.200
|
31
31
|
# The following 'home_pubsub_user' and 'home_pubsub_pwd' are optional
|
32
32
|
# RC will create a unique user/pwd for itself if this is not provided
|
33
33
|
# In a typical OMF install, you should not uncomment these lines
|
34
|
-
# (do so only if you need to manually set user/password for
|
34
|
+
# (do so only if you need to manually set user/password for
|
35
35
|
# your client to connect to your pubsub server)
|
36
|
-
#:pubsub_user: 'my_RC_name'
|
36
|
+
#:pubsub_user: 'my_RC_name'
|
37
37
|
#:pubsub_pwd: 'my_RC_password'
|
38
38
|
# set this to "true" if you have a DNS SRV record pointing to the
|
39
39
|
# real pubsub server hostname
|
@@ -45,7 +45,7 @@
|
|
45
45
|
# Name (i.e. unique HRN ID) of this resource
|
46
46
|
# Or this could also be passed as a command line parameter "--name"
|
47
47
|
# This is either a fully defined string, e.g. "my_resource_name"
|
48
|
-
# Or a string for which some values will be replaced by the running RC,
|
48
|
+
# Or a string for which some values will be replaced by the running RC,
|
49
49
|
# currently we support the values: %hostname%, %macaddr%, %fqdn%
|
50
50
|
# For example, if you use "some_prefix.%hostname%.some_suffix"
|
51
51
|
# Then if your hostname is 'node1', then your RC name will be
|
@@ -56,7 +56,7 @@
|
|
56
56
|
|
57
57
|
# Name (i.e. unique HRN ID) of the slice to which this resource is assigned
|
58
58
|
:slice: default_slice
|
59
|
-
|
59
|
+
|
60
60
|
# shrink the filesystem size before saving an image
|
61
61
|
# grow the filesystem to match the disk size after loading an image
|
62
62
|
# enabling this may slow down load/save significantly
|
@@ -9,3 +9,11 @@ class OmfRc::MessageProcessError < StandardError
|
|
9
9
|
super(msg)
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
# No method error that caused by configure/request unknown property
|
14
|
+
#
|
15
|
+
class OmfRc::UnknownPropertyError < NoMethodError
|
16
|
+
def initialize(msg = nil)
|
17
|
+
super(msg)
|
18
|
+
end
|
19
|
+
end
|
@@ -30,6 +30,10 @@ class OmfRc::ResourceFactory
|
|
30
30
|
resource = OmfRc::ResourceProxy::AbstractResource.new(type, opts, comm)
|
31
31
|
# Then extend this instance with relevant module identified by type
|
32
32
|
resource.extend("OmfRc::ResourceProxy::#{type.camelize}".constantize)
|
33
|
+
# Initiate property hash
|
34
|
+
resource.methods.each do |m|
|
35
|
+
resource.__send__(m) if m =~ /def_property_(.+)/
|
36
|
+
end
|
33
37
|
# Execute resource before_ready hook if any
|
34
38
|
resource.before_ready if resource.respond_to? :before_ready
|
35
39
|
resource
|
@@ -1,8 +1,28 @@
|
|
1
1
|
require 'omf_rc/deferred_process'
|
2
|
-
require 'omf_rc/
|
2
|
+
require 'omf_rc/omf_error'
|
3
3
|
require 'securerandom'
|
4
4
|
require 'hashie'
|
5
5
|
|
6
|
+
# OML Measurement Point (MP)
|
7
|
+
# This MP is for measurements about messages published by the Resource Proxy
|
8
|
+
class OmfRc::ResourceProxy::MPPublished < OML4R::MPBase
|
9
|
+
name :proxy_published
|
10
|
+
param :time, :type => :double # Time (s) when this message was published
|
11
|
+
param :uid, :type => :string # UID for this Resource Proxy
|
12
|
+
param :topic, :type => :string # Pubsub topic to publish this message to
|
13
|
+
param :msg_id, :type => :string # Unique ID this message
|
14
|
+
end
|
15
|
+
|
16
|
+
# OML Measurement Point (MP)
|
17
|
+
# This MP is for measurements about messages received by the Resource Proxy
|
18
|
+
class OmfRc::ResourceProxy::MPReceived < OML4R::MPBase
|
19
|
+
name :proxy_received
|
20
|
+
param :time, :type => :double # Time (s) when this message was received
|
21
|
+
param :uid, :type => :string # UID for this Resource Proxy
|
22
|
+
param :topic, :type => :string # Pubsub topic where this message came from
|
23
|
+
param :msg_id, :type => :string # Unique ID this message
|
24
|
+
end
|
25
|
+
|
6
26
|
class OmfRc::ResourceProxy::AbstractResource
|
7
27
|
# Time to wait before shutting down event loop, wait for deleting pubsub topics
|
8
28
|
DISCONNECT_WAIT = 5
|
@@ -12,7 +32,7 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
12
32
|
# @!attribute property
|
13
33
|
# @return [String] the resource's internal meta data storage
|
14
34
|
attr_accessor :uid, :hrn, :type, :comm, :property
|
15
|
-
attr_reader :opts, :children
|
35
|
+
attr_reader :opts, :children, :membership
|
16
36
|
|
17
37
|
# Initialisation
|
18
38
|
#
|
@@ -25,6 +45,7 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
25
45
|
# @option opts [String] :password pubsub user password
|
26
46
|
# @option opts [String] :server pubsub server domain
|
27
47
|
# @option opts [String] :property A hash for keeping internal state
|
48
|
+
# @option opts [hash] :instrument A hash for keeping instrumentation-related state
|
28
49
|
# @param [Comm] comm communicator instance, pass this to new resource proxy instance if want to use a common communicator instance.
|
29
50
|
def initialize(type, opts = nil, comm = nil)
|
30
51
|
@opts = Hashie::Mash.new(opts)
|
@@ -32,6 +53,7 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
32
53
|
@uid = @opts.uid || SecureRandom.uuid
|
33
54
|
@hrn = @opts.hrn
|
34
55
|
@children ||= []
|
56
|
+
@membership ||= []
|
35
57
|
|
36
58
|
@property = @opts.property || Hashie::Mash.new
|
37
59
|
|
@@ -64,9 +86,9 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
64
86
|
# If method missing, try the property mash
|
65
87
|
def method_missing(method_name, *args)
|
66
88
|
if (method_name =~ /request_(.+)/)
|
67
|
-
property.send($1)
|
89
|
+
property.key?($1) ? property.send($1) : (raise OmfRc::UnknownPropertyError)
|
68
90
|
elsif (method_name =~ /configure_(.+)/)
|
69
|
-
property.
|
91
|
+
property.key?($1) ? property.send("[]=", $1, *args) : (raise OmfRc::UnknownPropertyError)
|
70
92
|
else
|
71
93
|
super
|
72
94
|
end
|
@@ -149,16 +171,26 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
149
171
|
# Make hrn configurable through pubsub interface
|
150
172
|
def configure_hrn(hrn)
|
151
173
|
@hrn = hrn
|
174
|
+
@hrn
|
175
|
+
end
|
176
|
+
|
177
|
+
# Make resource part of the group topic, it will overwrite existing membership array
|
178
|
+
#
|
179
|
+
# @param [String] name of group topic
|
180
|
+
# @param [Array] name of group topics
|
181
|
+
def configure_membership(*args)
|
182
|
+
new_membership = [args[0]].flatten
|
183
|
+
@membership = new_membership
|
184
|
+
@membership.each do |m|
|
185
|
+
@comm.subscribe(m)
|
186
|
+
end
|
187
|
+
@membership
|
152
188
|
end
|
153
189
|
|
154
190
|
# Request child resources
|
155
|
-
# @return [Mash] child resource mash with uid and hrn
|
191
|
+
# @return [Hashie::Mash] child resource mash with uid and hrn
|
156
192
|
def request_child_resources(*args)
|
157
|
-
Hashie::Mash.new.
|
158
|
-
children.each do |c|
|
159
|
-
mash[c.uid] ||= c.hrn
|
160
|
-
end
|
161
|
-
end
|
193
|
+
children.map { |c| Hashie::Mash.new({ uid: c.uid, name: c.hrn }) }
|
162
194
|
end
|
163
195
|
|
164
196
|
# Publish an inform message
|
@@ -203,15 +235,45 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
203
235
|
end
|
204
236
|
end
|
205
237
|
@comm.publish(inform_to, inform_message)
|
238
|
+
OmfRc::ResourceProxy::MPPublished.inject(Time.now.to_f,
|
239
|
+
self.uid, inform_to, inform_message.msg_id) if OmfCommon::Measure.enabled?
|
206
240
|
end
|
207
241
|
|
208
242
|
private
|
209
243
|
|
244
|
+
# Find resource object based on topic name
|
245
|
+
def objects_by_topic(name)
|
246
|
+
if name == uid || membership.include?(name)
|
247
|
+
objs = [self]
|
248
|
+
else
|
249
|
+
objs = children.find_all { |v| v.uid == name || v.membership.include?(name)}
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def inform_to_address(obj, publish_to = nil)
|
254
|
+
publish_to || obj.uid
|
255
|
+
end
|
256
|
+
|
210
257
|
# Parse omf message and execute as instructed by the message
|
211
258
|
#
|
212
259
|
def process_omf_message(pubsub_item_payload, topic)
|
260
|
+
message = OmfCommon::Message.parse(pubsub_item_payload)
|
261
|
+
|
262
|
+
unless message.valid?
|
263
|
+
raise StandardError, "Invalid message received: #{pubsub_item_payload}. Please check protocol schema of version #{OmfCommon::PROTOCOL_VERSION}."
|
264
|
+
end
|
265
|
+
|
266
|
+
objects_by_topic(topic).each do |obj|
|
267
|
+
OmfRc::ResourceProxy::MPReceived.inject(Time.now.to_f,
|
268
|
+
self.uid, topic, message.msg_id) if OmfCommon::Measure.enabled?
|
269
|
+
execute_omf_operation(message, obj)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def execute_omf_operation(message, obj)
|
213
274
|
dp = OmfRc::DeferredProcess.new
|
214
275
|
|
276
|
+
# When successfully executed
|
215
277
|
dp.callback do |response|
|
216
278
|
response = Hashie::Mash.new(response)
|
217
279
|
case response.operation
|
@@ -231,68 +293,69 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
231
293
|
end
|
232
294
|
end
|
233
295
|
|
296
|
+
# When failed
|
234
297
|
dp.errback do |e|
|
235
298
|
inform(:failed, e)
|
236
299
|
end
|
237
300
|
|
301
|
+
# Fire the process
|
238
302
|
dp.fire do
|
239
|
-
message = OmfCommon::Message.parse(pubsub_item_payload)
|
240
|
-
# Get the context id, which will be included when informing
|
241
|
-
context_id = message.read_content("context_id")
|
242
|
-
|
243
|
-
obj = topic == uid ? self : children.find { |v| v.uid == topic }
|
244
|
-
|
245
303
|
begin
|
246
|
-
|
304
|
+
default_response = {
|
305
|
+
operation: message.operation,
|
306
|
+
context_id: message.context_id,
|
307
|
+
inform_to: inform_to_address(obj, message.publish_to)
|
308
|
+
}
|
247
309
|
|
248
310
|
case message.operation
|
249
311
|
when :create
|
250
|
-
|
251
|
-
|
252
|
-
result = obj.create(message.read_property(:type), create_opts)
|
312
|
+
new_opts = opts.dup.merge(uid: nil)
|
313
|
+
new_obj = obj.create(message.read_property(:type), new_opts)
|
253
314
|
message.each_property do |p|
|
254
315
|
unless p.attr('key') == 'type'
|
255
|
-
method_name =
|
256
|
-
|
257
|
-
end
|
258
|
-
end
|
259
|
-
result.after_initial_configured if result.respond_to? :after_initial_configured
|
260
|
-
{ operation: :create, resource_id: result.uid, context_id: context_id, inform_to: uid }
|
261
|
-
when :request
|
262
|
-
result = Hashie::Mash.new.tap do |mash|
|
263
|
-
message.read_element("//property").each do |p|
|
264
|
-
method_name = "request_#{p.attr('key')}"
|
265
|
-
mash[p.attr('key')] ||= obj.__send__(method_name, message.read_property(p.attr('key')))
|
316
|
+
method_name = "configure_#{p.attr('key')}"
|
317
|
+
new_obj.__send__(method_name, message.read_property(p.attr('key')))
|
266
318
|
end
|
267
319
|
end
|
268
|
-
|
269
|
-
|
320
|
+
new_obj.after_initial_configured if new_obj.respond_to? :after_initial_configured
|
321
|
+
default_response.merge(resource_id: new_obj.uid)
|
322
|
+
when :request, :configure
|
270
323
|
result = Hashie::Mash.new.tap do |mash|
|
271
|
-
message.read_element("//property")
|
272
|
-
|
273
|
-
|
324
|
+
properties = message.read_element("//property")
|
325
|
+
if message.operation == :request && properties.empty?
|
326
|
+
obj.request_available_properties.request.each do |r_p|
|
327
|
+
method_name = "request_#{r_p.to_s}"
|
328
|
+
mash[r_p] ||= obj.__send__(method_name)
|
329
|
+
end
|
330
|
+
else
|
331
|
+
properties.each do |p|
|
332
|
+
method_name = "#{message.operation.to_s}_#{p.attr('key')}"
|
333
|
+
mash[p.attr('key')] ||= obj.__send__(method_name, message.read_property(p.attr('key')))
|
334
|
+
end
|
274
335
|
end
|
275
336
|
end
|
276
|
-
|
337
|
+
default_response.merge(status: result)
|
277
338
|
when :release
|
278
339
|
resource_id = message.resource_id
|
279
|
-
|
340
|
+
default_response.merge(resource_id: obj.release(resource_id).uid)
|
280
341
|
when :inform
|
281
|
-
# We really don't care about inform messages which created from here
|
282
|
-
nil
|
342
|
+
nil # We really don't care about inform messages which created from here
|
283
343
|
else
|
284
|
-
raise
|
344
|
+
raise StandardError, <<-ERROR
|
345
|
+
Invalid message received (Unknown OMF operation #{message.operation}): #{pubsub_item_payload}.
|
346
|
+
Please check protocol schema of version #{OmfCommon::PROTOCOL_VERSION}.
|
347
|
+
ERROR
|
285
348
|
end
|
286
349
|
rescue => e
|
287
|
-
if (e.kind_of?
|
350
|
+
if (e.kind_of? OmfRc::UnknownPropertyError) && (message.operation == :configure || message.operation == :request)
|
288
351
|
msg = "Cannot #{message.operation} unknown property "+
|
289
352
|
"'#{message.read_element("//property")}' for resource '#{type}'"
|
290
353
|
logger.warn msg
|
291
|
-
raise OmfRc::MessageProcessError.new(context_id, obj.
|
354
|
+
raise OmfRc::MessageProcessError.new(message.context_id, inform_to_address(obj, message.publish_to), msg)
|
292
355
|
else
|
293
356
|
logger.error e.message
|
294
357
|
logger.error e.backtrace.join("\n")
|
295
|
-
raise OmfRc::MessageProcessError.new(context_id, obj.
|
358
|
+
raise OmfRc::MessageProcessError.new(message.context_id, inform_to_address(obj, message.publish_to), e.message)
|
296
359
|
end
|
297
360
|
end
|
298
361
|
end
|