omf_rc 6.0.0.pre.8 → 6.0.0.pre.9

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.
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