omf_rc 6.0.0.pre.8 → 6.0.0.pre.9
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/install_omf_rc +79 -0
- data/bin/omf_rc +52 -36
- data/config/config.yml +8 -0
- data/init/debian +51 -0
- data/init/fedora +54 -0
- data/init/run_omf_rc.sh +62 -0
- data/init/ubuntu +12 -0
- data/lib/omf_rc/omf_error.rb +5 -5
- data/lib/omf_rc/resource_factory.rb +7 -11
- data/lib/omf_rc/resource_proxy/abstract_resource.rb +327 -228
- data/lib/omf_rc/resource_proxy/application.rb +61 -56
- data/lib/omf_rc/resource_proxy/net.rb +2 -2
- data/lib/omf_rc/resource_proxy/node.rb +11 -2
- data/lib/omf_rc/resource_proxy/virtual_machine.rb +1 -1
- data/lib/omf_rc/resource_proxy/wlan.rb +2 -0
- data/lib/omf_rc/resource_proxy_dsl.rb +22 -1
- data/lib/omf_rc/util/common_tools.rb +2 -4
- data/lib/omf_rc/util/hostapd.rb +4 -3
- data/lib/omf_rc/util/ip.rb +8 -5
- data/lib/omf_rc/util/iw.rb +18 -8
- data/lib/omf_rc/util/sysfs.rb +14 -0
- data/lib/omf_rc/util/vmbuilder.rb +1 -1
- data/lib/omf_rc/util/wpa.rb +4 -3
- data/lib/omf_rc/version.rb +1 -1
- data/lib/omf_rc.rb +3 -1
- data/omf_rc.gemspec +4 -2
- data/test/omf_rc/message_process_error_spec.rb +3 -3
- data/test/omf_rc/resource_factory_spec.rb +14 -7
- data/test/omf_rc/resource_proxy/abstract_resource_spec.rb +47 -21
- data/test/omf_rc/resource_proxy/application_spec.rb +156 -119
- data/test/omf_rc/resource_proxy/mock_spec.rb +6 -1
- data/test/omf_rc/resource_proxy/node_spec.rb +32 -12
- data/test/omf_rc/resource_proxy_dsl_spec.rb +31 -19
- data/test/omf_rc/util/common_tools_spec.rb +8 -11
- data/test/omf_rc/util/ip_spec.rb +7 -1
- data/test/omf_rc/util/iw_spec.rb +18 -13
- data/test/omf_rc/util/mock_spec.rb +6 -1
- data/test/omf_rc/util/mod_spec.rb +17 -10
- data/test/test_helper.rb +3 -0
- metadata +51 -48
- data/config/omf_rc.yml +0 -70
- data/lib/omf_rc/resource_proxy/openflow_slice.rb +0 -79
- data/lib/omf_rc/resource_proxy/openflow_slice_factory.rb +0 -71
@@ -1,7 +1,8 @@
|
|
1
|
-
require 'omf_rc/deferred_process'
|
1
|
+
#require 'omf_rc/deferred_process'
|
2
2
|
require 'omf_rc/omf_error'
|
3
3
|
require 'securerandom'
|
4
4
|
require 'hashie'
|
5
|
+
require 'monitor'
|
5
6
|
|
6
7
|
# OML Measurement Point (MP)
|
7
8
|
# This MP is for measurements about messages published by the Resource Proxy
|
@@ -10,7 +11,7 @@ class OmfRc::ResourceProxy::MPPublished < OML4R::MPBase
|
|
10
11
|
param :time, :type => :double # Time (s) when this message was published
|
11
12
|
param :uid, :type => :string # UID for this Resource Proxy
|
12
13
|
param :topic, :type => :string # Pubsub topic to publish this message to
|
13
|
-
param :
|
14
|
+
param :mid, :type => :string # Unique ID this message
|
14
15
|
end
|
15
16
|
|
16
17
|
# OML Measurement Point (MP)
|
@@ -20,76 +21,85 @@ class OmfRc::ResourceProxy::MPReceived < OML4R::MPBase
|
|
20
21
|
param :time, :type => :double # Time (s) when this message was received
|
21
22
|
param :uid, :type => :string # UID for this Resource Proxy
|
22
23
|
param :topic, :type => :string # Pubsub topic where this message came from
|
23
|
-
param :
|
24
|
+
param :mid, :type => :string # Unique ID this message
|
24
25
|
end
|
25
26
|
|
26
27
|
class OmfRc::ResourceProxy::AbstractResource
|
28
|
+
include MonitorMixin
|
29
|
+
|
27
30
|
# Time to wait before shutting down event loop, wait for deleting pubsub topics
|
28
31
|
DISCONNECT_WAIT = 5
|
29
32
|
# Time to wait before releasing resource, wait for deleting pubsub topics
|
30
33
|
RELEASE_WAIT = 5
|
31
34
|
|
35
|
+
DEFAULT_CREATION_OPTS = {
|
36
|
+
suppress_create_message: false,
|
37
|
+
create_children_resources: true
|
38
|
+
}
|
39
|
+
|
32
40
|
# @!attribute property
|
33
41
|
# @return [String] the resource's internal meta data storage
|
34
42
|
attr_accessor :uid, :hrn, :type, :comm, :property
|
35
|
-
attr_reader :opts, :children, :membership
|
43
|
+
attr_reader :opts, :children, :membership, :creation_opts, :membership_topics
|
36
44
|
|
37
45
|
# Initialisation
|
38
46
|
#
|
39
47
|
# @param [Symbol] type resource proxy type
|
48
|
+
#
|
40
49
|
# @param [Hash] opts options to be initialised
|
41
50
|
# @option opts [String] :uid Unique identifier
|
42
51
|
# @option opts [String] :hrn Human readable name
|
43
|
-
# @option opts [
|
44
|
-
# @option opts [
|
45
|
-
#
|
46
|
-
# @
|
47
|
-
# @option
|
48
|
-
# @option
|
49
|
-
#
|
50
|
-
def initialize(type, opts =
|
52
|
+
# @option opts [Hash] :property A hash for keeping internal state
|
53
|
+
# @option opts [Hash] :instrument A hash for keeping instrumentation-related state
|
54
|
+
#
|
55
|
+
# @param [Hash] creation_opts options to control the resource creation process
|
56
|
+
# @option creation_opts [Boolean] :suppress_create_message Don't send an initial CREATION.OK Inform message
|
57
|
+
# @option creation_opts [Boolean] :create_children_resources Immediately create 'known' children resources, such as interfaces on nodes
|
58
|
+
#
|
59
|
+
def initialize(type, opts = {}, creation_opts = {}, &creation_callback)
|
51
60
|
@opts = Hashie::Mash.new(opts)
|
61
|
+
@creation_opts = Hashie::Mash.new(DEFAULT_CREATION_OPTS.merge(creation_opts))
|
62
|
+
|
52
63
|
@type = type
|
53
64
|
@uid = @opts.uid || SecureRandom.uuid
|
54
|
-
@hrn = @opts.hrn
|
65
|
+
@hrn = @opts.hrn && @opts.hrn.to_s
|
66
|
+
|
55
67
|
@children ||= []
|
56
68
|
@membership ||= []
|
69
|
+
@topics = []
|
70
|
+
@membership_topics ||= {}
|
71
|
+
|
72
|
+
# FIXME adding hrn to membership too?
|
73
|
+
#@membership << @hrn if @hrn
|
57
74
|
|
58
75
|
@property = @opts.property || Hashie::Mash.new
|
76
|
+
@property.merge!(@opts.except([:uid, :hrn, :property, :instrument]))
|
59
77
|
|
60
|
-
@
|
61
|
-
|
62
|
-
|
63
|
-
logger.info "CONNECTED: #{@comm.jid.inspect}"
|
64
|
-
|
65
|
-
# Once connection established, create a pubsub topic, then subscribe to it
|
66
|
-
@comm.create_topic(uid) do |s|
|
67
|
-
# Creating topic failed, no point to continue; clean up and disconnect
|
68
|
-
# Otherwise go subscribe to this pubsub topic
|
69
|
-
if s.error?
|
70
|
-
warn "Could not create topic '#{uid}', will shutdown, trying to clean up old topics. Please start it again once it has been shutdown."
|
71
|
-
disconnect
|
72
|
-
else
|
73
|
-
@comm.subscribe(uid)
|
74
|
-
end
|
78
|
+
OmfCommon.comm.subscribe(@hrn ? [@uid, @hrn] : @uid) do |t|
|
79
|
+
if t.id.to_s == @uid
|
80
|
+
@topics << t
|
75
81
|
end
|
76
|
-
end
|
77
82
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
83
|
+
if t.error?
|
84
|
+
warn "Could not create topic '#{uid}', will shutdown, trying to clean up old topics. Please start it again once it has been shutdown."
|
85
|
+
OmfCommon.comm.disconnect()
|
86
|
+
else
|
87
|
+
creation_callback.call(self) if creation_callback
|
88
|
+
copts = { res_id: self.resource_address, hrn: @hrn }.merge(@property)
|
89
|
+
t.inform(:creation_ok, copts, copts)
|
90
|
+
|
91
|
+
t.on_message(nil, @uid) do |imsg|
|
92
|
+
process_omf_message(imsg, t)
|
93
|
+
end
|
82
94
|
end
|
83
95
|
end
|
84
96
|
|
85
|
-
|
86
|
-
@comm.pubsub_event do |e|
|
87
|
-
logger.debug "PUBSUB GENERIC EVENT: #{e}"
|
88
|
-
end
|
97
|
+
super()
|
89
98
|
end
|
90
99
|
|
91
100
|
# If method missing, try the property mash
|
92
101
|
def method_missing(method_name, *args)
|
102
|
+
warn "Method missing: '#{method_name}'"
|
93
103
|
if (method_name =~ /request_(.+)/)
|
94
104
|
property.key?($1) ? property.send($1) : (raise OmfRc::UnknownPropertyError, method_name.to_s)
|
95
105
|
elsif (method_name =~ /configure_(.+)/)
|
@@ -99,57 +109,103 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
99
109
|
end
|
100
110
|
end
|
101
111
|
|
102
|
-
|
103
|
-
|
112
|
+
# Overwirte methods to add ghost methods
|
113
|
+
def methods
|
114
|
+
super + property.keys.map { |v| ["configure_#{v}".to_sym, "request_#{v}".to_sym] }.flatten
|
104
115
|
end
|
105
116
|
|
106
|
-
#
|
107
|
-
|
108
|
-
|
117
|
+
# Return the public 'routable' address for this resource
|
118
|
+
#
|
119
|
+
def resource_address()
|
120
|
+
@topics[0].address
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_binding
|
124
|
+
binding
|
109
125
|
end
|
110
126
|
|
111
127
|
# Try to clean up pubsub topics, and wait for DISCONNECT_WAIT seconds, then shutdown event machine loop
|
112
128
|
def disconnect
|
113
|
-
|
114
|
-
logger.info "Disconnecting #{hrn}(#{uid}) in #{DISCONNECT_WAIT} seconds"
|
115
|
-
EM.add_timer(DISCONNECT_WAIT) do
|
116
|
-
@comm.disconnect
|
117
|
-
end
|
129
|
+
OmfCommon.comm.disconnect
|
118
130
|
end
|
119
131
|
|
120
132
|
# Create a new resource in the context of this resource. This resource becomes parent, and newly created resource becomes child
|
121
133
|
#
|
122
134
|
# @param (see #initialize)
|
123
|
-
def create(type, opts =
|
135
|
+
def create(type, opts = {}, creation_opts = {}, &creation_callback)
|
124
136
|
proxy_info = OmfRc::ResourceFactory.proxy_list[type]
|
125
137
|
if proxy_info && proxy_info.create_by && !proxy_info.create_by.include?(self.type.to_sym)
|
126
138
|
raise StandardError, "Resource #{type} is not designed to be created by #{self.type}"
|
127
139
|
end
|
128
140
|
|
129
141
|
before_create(type, opts) if respond_to? :before_create
|
130
|
-
new_resource = OmfRc::ResourceFactory.
|
142
|
+
new_resource = OmfRc::ResourceFactory.create(type.to_sym, opts, creation_opts, &creation_callback)
|
131
143
|
after_create(new_resource) if respond_to? :after_create
|
132
|
-
|
144
|
+
|
145
|
+
self.synchronize do
|
146
|
+
children << new_resource
|
147
|
+
end
|
133
148
|
new_resource
|
134
149
|
end
|
135
150
|
|
136
|
-
# Release a resource
|
151
|
+
# Release a child resource
|
152
|
+
#
|
153
|
+
# @return [AbstractResource] Relsead child or nil if error
|
137
154
|
#
|
138
|
-
def release(
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
155
|
+
def release(res_id)
|
156
|
+
if (child = children.find { |v| v.uid.to_s == res_id.to_s })
|
157
|
+
if child.release_self()
|
158
|
+
self.synchronize do
|
159
|
+
children.delete(child)
|
160
|
+
end
|
161
|
+
child
|
162
|
+
else
|
163
|
+
child = nil
|
164
|
+
end
|
165
|
+
debug "#{child.uid} released"
|
143
166
|
else
|
144
|
-
#
|
145
|
-
|
146
|
-
|
167
|
+
debug "#{res_id} does not belong to #{self.uid}(#{self.hrn}) - #{children.map(&:uid).inspect}"
|
168
|
+
end
|
169
|
+
child
|
170
|
+
end
|
171
|
+
|
172
|
+
# Release this resource. Should ONLY be called by parent resource.
|
173
|
+
#
|
174
|
+
# Return true if successful
|
175
|
+
#
|
176
|
+
def release_self
|
177
|
+
# Release children resource recursively
|
178
|
+
children.each do |c|
|
179
|
+
if c.release_self
|
180
|
+
self.synchronize do
|
181
|
+
children.delete(c)
|
182
|
+
end
|
147
183
|
end
|
148
|
-
|
184
|
+
end
|
185
|
+
|
186
|
+
return false unless children.empty?
|
149
187
|
|
150
|
-
|
151
|
-
|
188
|
+
info "Releasing hrn: #{hrn}, uid: #{uid}"
|
189
|
+
self.before_release if self.respond_to? :before_release
|
190
|
+
props = {
|
191
|
+
res_id: resource_address
|
192
|
+
}
|
193
|
+
props[:hrn] = hrn if hrn
|
194
|
+
inform :released, props
|
195
|
+
|
196
|
+
# clean up topics
|
197
|
+
@topics.each do |t|
|
198
|
+
t.unsubscribe
|
152
199
|
end
|
200
|
+
|
201
|
+
@membership_topics.each_value do |t|
|
202
|
+
if t.respond_to? :delete_on_message_cbk_by_id
|
203
|
+
t.delete_on_message_cbk_by_id(@uid)
|
204
|
+
end
|
205
|
+
t.unsubscribe
|
206
|
+
end
|
207
|
+
|
208
|
+
true
|
153
209
|
end
|
154
210
|
|
155
211
|
# Return a list of all properties can be requested and configured
|
@@ -157,7 +213,7 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
157
213
|
def request_available_properties(*args)
|
158
214
|
Hashie::Mash.new(request: [], configure: []).tap do |mash|
|
159
215
|
methods.each do |m|
|
160
|
-
mash[$1] << $2.to_sym if m =~
|
216
|
+
mash[$1] << $2.to_sym if m =~ /^(request|configure)_(.+)/ && $2 != "available_properties"
|
161
217
|
end
|
162
218
|
end
|
163
219
|
end
|
@@ -167,6 +223,14 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
167
223
|
uid
|
168
224
|
end
|
169
225
|
|
226
|
+
def request_type(*args)
|
227
|
+
type
|
228
|
+
end
|
229
|
+
|
230
|
+
def configure_type(*args)
|
231
|
+
@type = type
|
232
|
+
end
|
233
|
+
|
170
234
|
# Make hrn accessible through pubsub interface
|
171
235
|
def request_hrn(*args)
|
172
236
|
hrn
|
@@ -174,33 +238,43 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
174
238
|
|
175
239
|
alias_method :request_name, :request_hrn
|
176
240
|
alias_method :name, :hrn
|
177
|
-
alias_method :name=, :hrn=
|
178
|
-
|
179
|
-
def request_type(*args)
|
180
|
-
type
|
181
|
-
end
|
182
241
|
|
183
242
|
# Make hrn configurable through pubsub interface
|
184
243
|
def configure_hrn(hrn)
|
185
|
-
|
244
|
+
self.synchronize do
|
245
|
+
@hrn = hrn
|
246
|
+
end
|
186
247
|
@hrn
|
187
248
|
end
|
188
249
|
|
250
|
+
alias_method :configure_name, :configure_hrn
|
251
|
+
alias_method :name=, :hrn=
|
252
|
+
|
189
253
|
# Make resource part of the group topic, it will overwrite existing membership array
|
190
254
|
#
|
191
255
|
# @param [String] name of group topic
|
192
256
|
# @param [Array] name of group topics
|
193
257
|
def configure_membership(*args)
|
194
258
|
new_membership = [args[0]].flatten
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
259
|
+
|
260
|
+
new_membership.each do |new_m|
|
261
|
+
unless @membership.include?(new_m)
|
262
|
+
OmfCommon.comm.subscribe(new_m) do |t|
|
263
|
+
if t.error?
|
264
|
+
warn "Group #{new_m} disappeared"
|
265
|
+
#EM.next_tick do
|
266
|
+
# @membership.delete(m)
|
267
|
+
#end
|
268
|
+
else
|
269
|
+
self.synchronize do
|
270
|
+
@membership << new_m
|
271
|
+
@membership_topics[new_m] = t
|
272
|
+
self.inform(:status, { membership: @membership }, t)
|
273
|
+
end
|
274
|
+
|
275
|
+
t.on_message(nil, @uid) do |imsg|
|
276
|
+
process_omf_message(imsg, t)
|
277
|
+
end
|
204
278
|
end
|
205
279
|
end
|
206
280
|
end
|
@@ -219,184 +293,209 @@ class OmfRc::ResourceProxy::AbstractResource
|
|
219
293
|
children.map { |c| Hashie::Mash.new({ uid: c.uid, name: c.hrn }) }
|
220
294
|
end
|
221
295
|
|
222
|
-
#
|
223
|
-
#
|
224
|
-
# @param [
|
225
|
-
|
226
|
-
|
296
|
+
# Parse omf message and execute as instructed by the message
|
297
|
+
#
|
298
|
+
# @param [OmfCommon::Message]
|
299
|
+
# @param [OmfCommon::Comm::Topic]
|
300
|
+
def process_omf_message(message, topic)
|
301
|
+
return unless check_guard(message)
|
227
302
|
|
228
|
-
|
229
|
-
|
230
|
-
unless inform_data.kind_of? Exception
|
231
|
-
raise ArgumentError, "FAILED message requires an Exception (or MessageProcessError)"
|
232
|
-
end
|
233
|
-
when :created, :released
|
234
|
-
unless inform_data.respond_to?(:resource_id) && !inform_data.resource_id.nil?
|
235
|
-
raise ArgumentError, "CREATED or RELEASED message requires inform_data object respond to resource_id"
|
236
|
-
end
|
237
|
-
when :status
|
238
|
-
unless inform_data.respond_to?(:status) && inform_data.status.kind_of?(Hash)
|
239
|
-
raise ArgumentError, "STATUS message requires a hash represents properties"
|
240
|
-
end
|
303
|
+
unless message.is_a? OmfCommon::Message
|
304
|
+
raise ArgumentError, "Expected OmfCommon::Message, but got '#{message.class}'"
|
241
305
|
end
|
242
306
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
i.element('resource_id', inform_data.resource_id)
|
251
|
-
i.element('resource_address', inform_data.resource_id)
|
252
|
-
when :status
|
253
|
-
inform_data.status.each_pair { |k, v| i.property(k, v) }
|
254
|
-
when :released
|
255
|
-
i.element('resource_id', inform_data.resource_id)
|
256
|
-
when :error, :warn
|
257
|
-
i.element("reason", (inform_data.message rescue inform_data))
|
258
|
-
logger.__send__(inform_type, (inform_data.message rescue inform_data))
|
259
|
-
when :failed
|
260
|
-
i.element("reason", inform_data.message)
|
307
|
+
unless message.valid?
|
308
|
+
raise StandardError, "Invalid message received: #{pubsub_item_payload}. Please check protocol schema of version #{OmfCommon::PROTOCOL_VERSION}."
|
309
|
+
end
|
310
|
+
|
311
|
+
objects_by_topic(topic.id.to_s).each do |obj|
|
312
|
+
if OmfCommon::Measure.enabled?
|
313
|
+
OmfRc::ResourceProxy::MPReceived.inject(Time.now.to_f, self.uid, topic, message.mid)
|
261
314
|
end
|
315
|
+
execute_omf_operation(message, obj, topic)
|
262
316
|
end
|
263
|
-
@comm.publish(inform_to, inform_message)
|
264
|
-
OmfRc::ResourceProxy::MPPublished.inject(Time.now.to_f,
|
265
|
-
self.uid, inform_to, inform_message.msg_id) if OmfCommon::Measure.enabled?
|
266
317
|
end
|
267
318
|
|
268
|
-
|
319
|
+
def execute_omf_operation(message, obj, topic)
|
320
|
+
begin
|
321
|
+
response_h = handle_message(message, obj)
|
322
|
+
rescue Exception => ex
|
323
|
+
err_resp = message.create_inform_reply_message()
|
324
|
+
err_resp[:reason] = ex.to_s
|
325
|
+
error "Encountered exception, returning ERROR message"
|
326
|
+
debug ex.message
|
327
|
+
debug ex.backtrace.join("\n")
|
328
|
+
return inform(:error, err_resp, topic)
|
329
|
+
end
|
269
330
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
331
|
+
case message.operation
|
332
|
+
#when :create
|
333
|
+
# inform(:creation_ok, response_h, topic)
|
334
|
+
when :request, :configure
|
335
|
+
inform(:status, response_h, topic)
|
336
|
+
when :release
|
337
|
+
OmfCommon.eventloop.after(RELEASE_WAIT) do
|
338
|
+
inform(:released, response_h, topic) if response_h[:res_id]
|
339
|
+
end
|
276
340
|
end
|
277
341
|
end
|
278
342
|
|
279
|
-
|
280
|
-
|
343
|
+
# Handling all messages, then delegate them to individual handler
|
344
|
+
def handle_message(message, obj)
|
345
|
+
response = message.create_inform_reply_message()
|
346
|
+
response.replyto replyto_address(obj, message.replyto)
|
347
|
+
|
348
|
+
case message.operation
|
349
|
+
when :create
|
350
|
+
handle_create_message(message, obj, response)
|
351
|
+
when :request
|
352
|
+
response = handle_request_message(message, obj, response)
|
353
|
+
when :configure
|
354
|
+
handle_configure_message(message, obj, response)
|
355
|
+
when :release
|
356
|
+
handle_release_message(message, obj, response)
|
357
|
+
when :inform
|
358
|
+
nil # We really don't care about inform messages which created from here
|
359
|
+
else
|
360
|
+
raise StandardError, <<-ERROR
|
361
|
+
Invalid message received (Unknown OMF operation #{message.operation}): #{message}.
|
362
|
+
Please check protocol schema of version #{OmfCommon::PROTOCOL_VERSION}.
|
363
|
+
ERROR
|
364
|
+
end
|
365
|
+
response
|
281
366
|
end
|
282
367
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
368
|
+
def handle_create_message(message, obj, response)
|
369
|
+
new_name = message[:name] || message[:hrn]
|
370
|
+
new_opts = message.properties.merge({ hrn: new_name })
|
371
|
+
new_obj = obj.create(message[:type], new_opts) do |new_obj|
|
372
|
+
begin
|
373
|
+
response[:res_id] = new_obj.resource_address
|
287
374
|
|
288
|
-
|
289
|
-
|
375
|
+
exclude = [:type, :hrn, :name]
|
376
|
+
message.each_property do |key, value|
|
377
|
+
unless exclude.include?(key)
|
378
|
+
method_name = "configure_#{key}"
|
379
|
+
response[key] = new_obj.__send__(method_name, value)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
response[:hrn] = new_obj.hrn
|
383
|
+
response[:uid] = new_obj.uid
|
384
|
+
response[:type] = new_obj.type
|
385
|
+
|
386
|
+
new_obj.after_initial_configured if new_obj.respond_to? :after_initial_configured
|
387
|
+
|
388
|
+
# self here is the parent
|
389
|
+
self.inform(:creation_ok, response)
|
390
|
+
rescue Exception => ex
|
391
|
+
err_resp = message.create_inform_reply_message()
|
392
|
+
err_resp[:reason] = ex.to_s
|
393
|
+
error "Encountered exception, returning ERROR message"
|
394
|
+
debug ex.message
|
395
|
+
debug ex.backtrace.join("\n")
|
396
|
+
return self.inform(:error, err_resp)
|
397
|
+
end
|
290
398
|
end
|
399
|
+
end
|
291
400
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
401
|
+
def handle_configure_message(message, obj, response)
|
402
|
+
message.each_property do |key, value|
|
403
|
+
method_name = "#{message.operation.to_s}_#{key}"
|
404
|
+
p_value = message[key]
|
405
|
+
response[key] ||= obj.__send__(method_name, p_value)
|
296
406
|
end
|
297
407
|
end
|
298
408
|
|
299
|
-
def
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
@comm.subscribe(new_uid) do
|
310
|
-
inform(:created, response)
|
311
|
-
end
|
312
|
-
end
|
313
|
-
when :request, :configure
|
314
|
-
inform(:status, response)
|
315
|
-
when :release
|
316
|
-
EM.add_timer(RELEASE_WAIT) do
|
317
|
-
inform(:released, response)
|
318
|
-
end
|
409
|
+
def handle_request_message(message, obj, response)
|
410
|
+
allowed_properties = obj.request_available_properties.request - [:message]
|
411
|
+
|
412
|
+
have_unbound = false
|
413
|
+
|
414
|
+
message.each_unbound_request_property do |name|
|
415
|
+
puts "NAME>> #{name.inspect}"
|
416
|
+
|
417
|
+
unless allowed_properties.include?(name.to_sym)
|
418
|
+
raise ArgumentError, "Unknown 'requestable' property '#{name}'. Allowed properties are: #{allowed_properties.join(', ')}"
|
319
419
|
end
|
420
|
+
method_name = "request_#{name}"
|
421
|
+
response[name] = obj.__send__(method_name)
|
422
|
+
have_unbound = true
|
423
|
+
end
|
424
|
+
unless have_unbound
|
425
|
+
# return ALL properties
|
426
|
+
allowed_properties.each do |name|
|
427
|
+
method_name = "request_#{name}"
|
428
|
+
response[name] = obj.__send__(method_name)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
response
|
432
|
+
end
|
433
|
+
|
434
|
+
def handle_release_message(message, obj, response)
|
435
|
+
res_id = message.res_id
|
436
|
+
released_obj = obj.release(res_id)
|
437
|
+
# TODO: Under what circumstances would 'realease_obj' be NIL
|
438
|
+
#
|
439
|
+
# When release message send to a group, for bulk releasing,
|
440
|
+
# the proxy might not be aware of a res_id it received
|
441
|
+
response[:res_id] = released_obj.resource_address if released_obj
|
442
|
+
response
|
443
|
+
end
|
444
|
+
|
445
|
+
|
446
|
+
# Publish an inform message
|
447
|
+
# @param [Symbol] itype the type of inform message
|
448
|
+
# @param [Hash | Hashie::Mash | Exception | String] inform_data the type of inform message
|
449
|
+
def inform(itype, inform_data, topic = nil)
|
450
|
+
topic ||= @topics.first
|
451
|
+
|
452
|
+
if inform_data.is_a? Hash
|
453
|
+
inform_data = Hashie::Mash.new(inform_data) if inform_data.class == Hash
|
454
|
+
message = OmfCommon::Message.create_inform_message(itype.to_s.upcase, inform_data.dup)
|
455
|
+
else
|
456
|
+
message = inform_data
|
320
457
|
end
|
321
458
|
|
322
|
-
|
323
|
-
|
324
|
-
|
459
|
+
message.itype = itype
|
460
|
+
unless itype == :released
|
461
|
+
message[:uid] ||= self.uid
|
462
|
+
message[:type] ||= self.type
|
463
|
+
message[:hrn] ||= self.hrn
|
325
464
|
end
|
326
465
|
|
327
|
-
|
328
|
-
dp.fire do
|
329
|
-
begin
|
330
|
-
default_response = {
|
331
|
-
operation: message.operation,
|
332
|
-
context_id: message.msg_id,
|
333
|
-
inform_to: inform_to_address(obj, message.publish_to)
|
334
|
-
}
|
466
|
+
topic.publish(message)
|
335
467
|
|
336
|
-
|
468
|
+
OmfRc::ResourceProxy::MPPublished.inject(Time.now.to_f,
|
469
|
+
self.uid, replyto, inform_message.mid) if OmfCommon::Measure.enabled?
|
470
|
+
end
|
337
471
|
|
338
|
-
|
339
|
-
guard_check = guard.element_children.all? do |g|
|
340
|
-
obj.__send__("request_#{g.attr('key')}") == g.content.ducktype
|
341
|
-
end
|
342
|
-
next nil unless guard_check
|
343
|
-
end
|
472
|
+
private
|
344
473
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
properties.each do |p|
|
369
|
-
method_name = "#{message.operation.to_s}_#{p.attr('key')}"
|
370
|
-
p_value = message.read_property(p.attr('key'), obj.get_binding)
|
371
|
-
mash[p.attr('key')] ||= obj.__send__(method_name, p_value)
|
372
|
-
end
|
373
|
-
end
|
374
|
-
end
|
375
|
-
# Always return uid
|
376
|
-
result.uid = obj.uid
|
377
|
-
default_response.merge(status: result)
|
378
|
-
when :release
|
379
|
-
resource_id = message.resource_id
|
380
|
-
released_obj = obj.release(resource_id)
|
381
|
-
released_obj ? default_response.merge(resource_id: released_obj.uid) : nil
|
382
|
-
when :inform
|
383
|
-
nil # We really don't care about inform messages which created from here
|
384
|
-
else
|
385
|
-
raise StandardError, <<-ERROR
|
386
|
-
Invalid message received (Unknown OMF operation #{message.operation}): #{pubsub_item_payload}.
|
387
|
-
Please check protocol schema of version #{OmfCommon::PROTOCOL_VERSION}.
|
388
|
-
ERROR
|
389
|
-
end
|
390
|
-
rescue => e
|
391
|
-
if (e.kind_of? OmfRc::UnknownPropertyError) && (message.operation == :configure || message.operation == :request)
|
392
|
-
msg = "Cannot #{message.operation} unknown property '#{e.message}' for resource '#{obj.type}'. Original message fragment: " +
|
393
|
-
"'#{message.read_element("property")}'"
|
394
|
-
logger.warn msg
|
395
|
-
raise OmfRc::MessageProcessError.new(message.context_id, inform_to_address(obj, message.publish_to), msg)
|
474
|
+
# Find resource object based on topic name
|
475
|
+
def objects_by_topic(name)
|
476
|
+
if name == uid || membership.include?(name)
|
477
|
+
objs = [self]
|
478
|
+
else
|
479
|
+
objs = children.find_all { |v| v.uid == name || v.membership.include?(name)}
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
def replyto_address(obj, replyto = nil)
|
484
|
+
replyto || obj.uid
|
485
|
+
end
|
486
|
+
|
487
|
+
def check_guard(message)
|
488
|
+
guard = message.guard
|
489
|
+
|
490
|
+
if guard.nil? || guard.empty?
|
491
|
+
return true
|
492
|
+
else
|
493
|
+
guard.keys.all? do |key|
|
494
|
+
value = self.__send__("request_#{key}")
|
495
|
+
if value.kind_of? Symbol
|
496
|
+
value.to_s == guard[key].to_s
|
396
497
|
else
|
397
|
-
|
398
|
-
logger.error e.backtrace.join("\n")
|
399
|
-
raise OmfRc::MessageProcessError.new(message.context_id, inform_to_address(obj, message.publish_to), e.message)
|
498
|
+
value == guard[key]
|
400
499
|
end
|
401
500
|
end
|
402
501
|
end
|