omf_rc 6.0.0.pre.6 → 6.0.0.pre.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|