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.
Files changed (43) hide show
  1. data/bin/install_omf_rc +79 -0
  2. data/bin/omf_rc +52 -36
  3. data/config/config.yml +8 -0
  4. data/init/debian +51 -0
  5. data/init/fedora +54 -0
  6. data/init/run_omf_rc.sh +62 -0
  7. data/init/ubuntu +12 -0
  8. data/lib/omf_rc/omf_error.rb +5 -5
  9. data/lib/omf_rc/resource_factory.rb +7 -11
  10. data/lib/omf_rc/resource_proxy/abstract_resource.rb +327 -228
  11. data/lib/omf_rc/resource_proxy/application.rb +61 -56
  12. data/lib/omf_rc/resource_proxy/net.rb +2 -2
  13. data/lib/omf_rc/resource_proxy/node.rb +11 -2
  14. data/lib/omf_rc/resource_proxy/virtual_machine.rb +1 -1
  15. data/lib/omf_rc/resource_proxy/wlan.rb +2 -0
  16. data/lib/omf_rc/resource_proxy_dsl.rb +22 -1
  17. data/lib/omf_rc/util/common_tools.rb +2 -4
  18. data/lib/omf_rc/util/hostapd.rb +4 -3
  19. data/lib/omf_rc/util/ip.rb +8 -5
  20. data/lib/omf_rc/util/iw.rb +18 -8
  21. data/lib/omf_rc/util/sysfs.rb +14 -0
  22. data/lib/omf_rc/util/vmbuilder.rb +1 -1
  23. data/lib/omf_rc/util/wpa.rb +4 -3
  24. data/lib/omf_rc/version.rb +1 -1
  25. data/lib/omf_rc.rb +3 -1
  26. data/omf_rc.gemspec +4 -2
  27. data/test/omf_rc/message_process_error_spec.rb +3 -3
  28. data/test/omf_rc/resource_factory_spec.rb +14 -7
  29. data/test/omf_rc/resource_proxy/abstract_resource_spec.rb +47 -21
  30. data/test/omf_rc/resource_proxy/application_spec.rb +156 -119
  31. data/test/omf_rc/resource_proxy/mock_spec.rb +6 -1
  32. data/test/omf_rc/resource_proxy/node_spec.rb +32 -12
  33. data/test/omf_rc/resource_proxy_dsl_spec.rb +31 -19
  34. data/test/omf_rc/util/common_tools_spec.rb +8 -11
  35. data/test/omf_rc/util/ip_spec.rb +7 -1
  36. data/test/omf_rc/util/iw_spec.rb +18 -13
  37. data/test/omf_rc/util/mock_spec.rb +6 -1
  38. data/test/omf_rc/util/mod_spec.rb +17 -10
  39. data/test/test_helper.rb +3 -0
  40. metadata +51 -48
  41. data/config/omf_rc.yml +0 -70
  42. data/lib/omf_rc/resource_proxy/openflow_slice.rb +0 -79
  43. 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 :msg_id, :type => :string # Unique ID this message
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 :msg_id, :type => :string # Unique ID this message
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 [String] :dsl Which pubsub DSL to be used for pubsub communication
44
- # @option opts [String] :user pubsub user id
45
- # @option opts [String] :password pubsub user password
46
- # @option opts [String] :server pubsub server domain
47
- # @option opts [String] :property A hash for keeping internal state
48
- # @option opts [hash] :instrument A hash for keeping instrumentation-related state
49
- # @param [Comm] comm communicator instance, pass this to new resource proxy instance if want to use a common communicator instance.
50
- def initialize(type, opts = nil, comm = nil)
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
- @comm = comm || OmfCommon::Comm.new(@opts.dsl)
61
- # Fire when connection to pubsub server established
62
- @comm.when_ready do
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
- # Fire when message published
79
- @comm.topic_event do |e|
80
- e.items.each do |item|
81
- process_omf_message(item.payload, e.node)
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
- # Generic pubsub event
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
- def get_binding
103
- binding
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
- # Connect to pubsub server
107
- def connect
108
- @comm.connect(opts.user, opts.password, opts.server)
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
- @comm.disconnect(delete_affiliations: true)
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 = nil)
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.new(type.to_sym, opts, @comm)
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
- children << new_resource
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(resource_id)
139
- obj = children.find { |v| v.uid == resource_id }
140
- if obj.nil?
141
- warn "#{resource_id} does not belong to #{self.uid}(#{self.hrn})"
142
- nil
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
- # Release children resource recursively
145
- obj.children.each do |c|
146
- obj.release(c.uid)
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
- obj.before_release if obj.respond_to? :before_release
184
+ end
185
+
186
+ return false unless children.empty?
149
187
 
150
- @comm.delete_topic(obj.uid)
151
- children.delete(obj)
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 =~ /(request|configure)_(.+)/ && $2 != "available_properties"
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
- @hrn = hrn
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
- new_membership.each do |n_m|
196
- @membership << n_m unless @membership.include?(n_m)
197
- end
198
- @membership.each do |m|
199
- @comm.subscribe(m) do |stanza|
200
- if stanza.error?
201
- warn "Group #{m} disappeared"
202
- EM.next_tick do
203
- @membership.delete(m)
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
- # Publish an inform message
223
- # @param [Symbol] inform_type the type of inform message
224
- # @param [Hash | Hashie::Mash | Exception | String] inform_data the type of inform message
225
- def inform(inform_type, inform_data)
226
- inform_data = Hashie::Mash.new(inform_data) if inform_data.class == Hash
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
- case inform_type
229
- when :failed
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
- context_id = inform_data.context_id if inform_data.respond_to? :context_id
244
- inform_to = inform_data.inform_to if inform_data.respond_to? :inform_to
245
- inform_to ||= self.uid
246
-
247
- inform_message = OmfCommon::Message.inform(inform_type.to_s.upcase, context_id) do |i|
248
- case inform_type
249
- when :created
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
- private
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
- # Find resource object based on topic name
271
- def objects_by_topic(name)
272
- if name == uid || membership.include?(name)
273
- objs = [self]
274
- else
275
- objs = children.find_all { |v| v.uid == name || v.membership.include?(name)}
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
- def inform_to_address(obj, publish_to = nil)
280
- publish_to || obj.uid
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
- # Parse omf message and execute as instructed by the message
284
- #
285
- def process_omf_message(pubsub_item_payload, topic)
286
- message = OmfCommon::Message.parse(pubsub_item_payload)
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
- unless message.valid?
289
- raise StandardError, "Invalid message received: #{pubsub_item_payload}. Please check protocol schema of version #{OmfCommon::PROTOCOL_VERSION}."
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
- objects_by_topic(topic).each do |obj|
293
- OmfRc::ResourceProxy::MPReceived.inject(Time.now.to_f,
294
- self.uid, topic, message.msg_id) if OmfCommon::Measure.enabled?
295
- execute_omf_operation(message, obj)
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 execute_omf_operation(message, obj)
300
- dp = OmfRc::DeferredProcess.new
301
-
302
- # When successfully executed
303
- dp.callback do |response|
304
- response = Hashie::Mash.new(response)
305
- case response.operation
306
- when :create
307
- new_uid = response.resource_id
308
- @comm.create_topic(new_uid) do
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
- # When failed
323
- dp.errback do |e|
324
- inform(:failed, e)
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
- # Fire the process
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
- guard = message.read_element("guard").first
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
- unless guard.nil? || guard.element_children.empty?
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
- case message.operation
346
- when :create
347
- new_name = message.read_property(:name) || message.read_property(:hrn)
348
- new_opts = opts.dup.merge(uid: nil, hrn: new_name)
349
- new_obj = obj.create(message.read_property(:type), new_opts)
350
- message.each_property do |p|
351
- unless %w(type hrn name).include?(p.attr('key'))
352
- method_name = "configure_#{p.attr('key')}"
353
- p_value = message.read_property(p.attr('key'), new_obj.get_binding)
354
- new_obj.__send__(method_name, p_value)
355
- end
356
- end
357
- new_obj.after_initial_configured if new_obj.respond_to? :after_initial_configured
358
- default_response.merge(resource_id: new_obj.uid)
359
- when :request, :configure
360
- result = Hashie::Mash.new.tap do |mash|
361
- properties = message.read_element("property")
362
- if message.operation == :request && properties.empty?
363
- obj.request_available_properties.request.each do |r_p|
364
- method_name = "request_#{r_p.to_s}"
365
- mash[r_p] ||= obj.__send__(method_name)
366
- end
367
- else
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
- logger.error e.message
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