omf_rc 6.0.0.pre.5 → 6.0.0.pre.6

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 (45) hide show
  1. data/Rakefile +0 -6
  2. data/bin/omf_rc +2 -2
  3. data/lib/omf_rc/resource_factory.rb +10 -4
  4. data/lib/omf_rc/resource_proxy/abstract_resource.rb +120 -79
  5. data/lib/omf_rc/resource_proxy/generic_application.rb +471 -0
  6. data/lib/omf_rc/resource_proxy/net.rb +7 -0
  7. data/lib/omf_rc/resource_proxy/node.rb +33 -7
  8. data/lib/omf_rc/resource_proxy/openflow_slice.rb +79 -0
  9. data/lib/omf_rc/resource_proxy/openflow_slice_factory.rb +71 -0
  10. data/lib/omf_rc/resource_proxy/wlan.rb +20 -0
  11. data/lib/omf_rc/resource_proxy_dsl.rb +142 -8
  12. data/lib/omf_rc/util/common_tools.rb +61 -0
  13. data/lib/omf_rc/util/hostapd.rb +52 -0
  14. data/lib/omf_rc/util/ip.rb +28 -0
  15. data/lib/omf_rc/util/iw.rb +119 -6
  16. data/lib/omf_rc/util/mock.rb +2 -1
  17. data/lib/omf_rc/util/openflow_tools.rb +103 -0
  18. data/lib/omf_rc/util/platform_tools.rb +164 -0
  19. data/lib/omf_rc/util/wpa.rb +42 -0
  20. data/lib/omf_rc/version.rb +1 -1
  21. data/omf_rc.gemspec +3 -1
  22. data/test/fixture/ip/addr_show +5 -0
  23. data/test/fixture/iw/info +4 -0
  24. data/test/fixture/sys/class/ieee80211/phy0/device/uevent +6 -0
  25. data/test/fixture/sys/class/ieee80211/phy0/uevent +0 -0
  26. data/test/fixture/sys/class/net/eth0/device/uevent +6 -0
  27. data/test/fixture/sys/class/net/eth0/uevent +2 -0
  28. data/test/fixture/sys/class/net/wlan0/device/uevent +6 -0
  29. data/test/fixture/sys/class/net/wlan0/uevent +3 -0
  30. data/test/omf_rc/message_process_error_spec.rb +11 -0
  31. data/test/omf_rc/resource_factory_spec.rb +8 -1
  32. data/test/omf_rc/resource_proxy/abstract_resource_spec.rb +57 -1
  33. data/test/omf_rc/resource_proxy/generic_application_spec.rb +347 -0
  34. data/test/omf_rc/resource_proxy/mock_spec.rb +15 -0
  35. data/test/omf_rc/resource_proxy/node_spec.rb +32 -1
  36. data/test/omf_rc/resource_proxy_dsl_spec.rb +81 -10
  37. data/test/omf_rc/util/common_tools_spec.rb +30 -0
  38. data/test/omf_rc/util/ip_spec.rb +51 -0
  39. data/test/omf_rc/util/iw_spec.rb +136 -25
  40. data/test/omf_rc/util/mock_spec.rb +26 -0
  41. data/test/omf_rc/util/mod_spec.rb +8 -11
  42. data/test/test_helper.rb +11 -0
  43. metadata +62 -6
  44. data/lib/omf_rc/resource_proxy/wifi.rb +0 -8
  45. data/test/mock_helper.rb +0 -15
data/Rakefile CHANGED
@@ -8,9 +8,3 @@ Rake::TestTask.new do |t|
8
8
  t.pattern = "test/**/*_spec.rb"
9
9
  t.verbose = true
10
10
  end
11
-
12
- Rake::TestTask.new(:integration) do |t|
13
- t.libs << 'integration_test'
14
- t.pattern = "integration_test/**/*_spec.rb"
15
- t.verbose = true
16
- end
data/bin/omf_rc CHANGED
@@ -6,7 +6,7 @@ require 'omf_rc/resource_factory'
6
6
  $stdout.sync = true
7
7
 
8
8
  options = {
9
- uid: 'interlagos'
9
+ uid: `hostname`.chomp
10
10
  }
11
11
 
12
12
  executable_name = File.basename($PROGRAM_NAME)
@@ -26,7 +26,7 @@ option_parser = OptionParser.new do |opts|
26
26
  options[:server] = server
27
27
  end
28
28
 
29
- opts.on("-t TOPIC", "PubSub topic to create, also becomes the uid of the resource") do |topic|
29
+ opts.on("-t TOPIC", "PubSub topic to create, also becomes the uid of the resource, default to hostname") do |topic|
30
30
  options[:uid] = topic
31
31
  end
32
32
 
@@ -7,7 +7,7 @@ require 'omf_rc/resource_proxy/abstract_resource'
7
7
  #
8
8
  class OmfRc::ResourceFactory
9
9
  # List of registered resource proxies
10
- @@proxy_list = []
10
+ @@proxy_list = Hashie::Mash.new
11
11
 
12
12
  # By default, we use xmpp dsl, which based on blather
13
13
  DEFAULT_OPTS = {
@@ -21,7 +21,9 @@ class OmfRc::ResourceFactory
21
21
  #
22
22
  # @see OmfRc::ResourceProxy::AbstractResource
23
23
  def new(type, opts = nil, comm = nil, &block)
24
- raise ArgumentError, "Resource type not found: #{type.to_s}" unless @@proxy_list.include?(type)
24
+ unless @@proxy_list.include?(type)
25
+ raise ArgumentError, "Resource type not found: #{type.to_s}" unless @@proxy_list.include?(type)
26
+ end
25
27
  type = type.to_s
26
28
  opts = opts ? DEFAULT_OPTS.merge(opts) : DEFAULT_OPTS
27
29
  # Create a new instance of abstract resource
@@ -39,8 +41,12 @@ class OmfRc::ResourceFactory
39
41
  end
40
42
 
41
43
  # Add a proxy to the list
42
- def register_proxy(proxy)
43
- @@proxy_list << proxy unless @@proxy_list.include?(proxy)
44
+ def register_proxy(proxy_opts)
45
+ if @@proxy_list.has_key? proxy_opts[:name]
46
+ raise StandardError, "Resource has been registered already"
47
+ else
48
+ @@proxy_list.update(proxy_opts)
49
+ end
44
50
  end
45
51
 
46
52
  # Require files from default resource proxy library folder
@@ -12,7 +12,7 @@ class OmfRc::ResourceProxy::AbstractResource
12
12
  # @!attribute property
13
13
  # @return [String] the resource's internal meta data storage
14
14
  attr_accessor :uid, :hrn, :type, :comm, :property
15
- attr_reader :opts, :children, :host
15
+ attr_reader :opts, :children
16
16
 
17
17
  # Initialisation
18
18
  #
@@ -32,20 +32,19 @@ class OmfRc::ResourceProxy::AbstractResource
32
32
  @uid = @opts.uid || SecureRandom.uuid
33
33
  @hrn = @opts.hrn
34
34
  @children ||= []
35
- @host = nil
35
+
36
36
  @property = @opts.property || Hashie::Mash.new
37
37
 
38
38
  @comm = comm || OmfCommon::Comm.new(@opts.dsl)
39
39
  # Fire when connection to pubsub server established
40
40
  @comm.when_ready do
41
41
  logger.info "CONNECTED: #{@comm.jid.inspect}"
42
- @host = @comm.jid.domain
43
42
 
44
43
  # Once connection established, create a pubsub topic, then subscribe to it
45
- @comm.create_topic(uid, host) do |s|
44
+ @comm.create_topic(uid) do |s|
46
45
  # Creating topic failed, no point to continue; clean up and disconnect
47
46
  # Otherwise go subscribe to this pubsub topic
48
- s.error? ? disconnect : @comm.subscribe(uid, host)
47
+ s.error? ? disconnect : @comm.subscribe(uid)
49
48
  end
50
49
  end
51
50
 
@@ -62,6 +61,17 @@ class OmfRc::ResourceProxy::AbstractResource
62
61
  end
63
62
  end
64
63
 
64
+ # If method missing, try the property mash
65
+ def method_missing(method_name, *args)
66
+ if (method_name =~ /request_(.+)/)
67
+ property.send($1) || super
68
+ elsif (method_name =~ /configure_(.+)/)
69
+ property.send($1) ? property.send("[]=", $1, *args) : super
70
+ else
71
+ super
72
+ end
73
+ end
74
+
65
75
  # Connect to pubsub server
66
76
  def connect
67
77
  @comm.connect(opts.user, opts.password, opts.server)
@@ -69,11 +79,11 @@ class OmfRc::ResourceProxy::AbstractResource
69
79
 
70
80
  # Try to clean up pubsub topics, and wait for DISCONNECT_WAIT seconds, then shutdown event machine loop
71
81
  def disconnect
72
- @comm.affiliations(host) do |a|
82
+ @comm.affiliations do |a|
73
83
  my_pubsub_topics = a[:owner] ? a[:owner].size : 0
74
84
  if my_pubsub_topics > 0
75
85
  logger.info "Cleaning #{my_pubsub_topics} pubsub topic(s)"
76
- a[:owner].each { |topic| @comm.delete_topic(topic, host) }
86
+ a[:owner].each { |topic| @comm.delete_topic(topic) }
77
87
  else
78
88
  logger.info "Disconnecting now"
79
89
  @comm.disconnect
@@ -89,27 +99,36 @@ class OmfRc::ResourceProxy::AbstractResource
89
99
  #
90
100
  # @param (see #initialize)
91
101
  def create(type, opts = nil)
92
- before_create if respond_to? :before_create
102
+ proxy_info = OmfRc::ResourceFactory.proxy_list[type]
103
+ if proxy_info && proxy_info.create_by && !proxy_info.create_by.include?(self.type.to_sym)
104
+ raise StandardError, "Resource #{type} is not designed to be created by #{self.type}"
105
+ end
106
+
107
+ before_create(type, opts) if respond_to? :before_create
93
108
  new_resource = OmfRc::ResourceFactory.new(type.to_sym, opts, @comm)
109
+ after_create(new_resource) if respond_to? :after_create
94
110
  children << new_resource
95
111
  new_resource
96
112
  end
97
113
 
98
114
  # Release a resource
99
115
  #
100
- def release
101
- pubsub_topics_left = []
102
- children.each do |c|
103
- c.before_release if c.respond_to? :before_release
104
- pubsub_topics_left << c.uid
105
- end.clear
106
- before_release if respond_to? :before_release
107
- pubsub_topics_left
116
+ def release(resource_id)
117
+ obj = children.find { |v| v.uid == resource_id }
118
+ raise StandardError, "Resource #{resource_id} could not be found" if obj.nil?
119
+
120
+ # Release children resource recursively
121
+ obj.children.each do |c|
122
+ obj.release(c.uid)
123
+ end
124
+ obj.before_release if obj.respond_to? :before_release
125
+
126
+ children.delete(obj)
108
127
  end
109
128
 
110
129
  # Return a list of all properties can be requested and configured
111
130
  #
112
- def request_available_properties
131
+ def request_available_properties(*args)
113
132
  Hashie::Mash.new(request: [], configure: []).tap do |mash|
114
133
  methods.each do |m|
115
134
  mash[$1] << $2.to_sym if m =~ /(request|configure)_(.+)/ && $2 != "available_properties"
@@ -118,12 +137,12 @@ class OmfRc::ResourceProxy::AbstractResource
118
137
  end
119
138
 
120
139
  # Make uid accessible through pubsub interface
121
- def request_uid
140
+ def request_uid(*args)
122
141
  uid
123
142
  end
124
143
 
125
144
  # Make hrn accessible through pubsub interface
126
- def request_hrn
145
+ def request_hrn(*args)
127
146
  hrn
128
147
  end
129
148
 
@@ -134,7 +153,7 @@ class OmfRc::ResourceProxy::AbstractResource
134
153
 
135
154
  # Request child resources
136
155
  # @return [Mash] child resource mash with uid and hrn
137
- def request_child_resources
156
+ def request_child_resources(*args)
138
157
  Hashie::Mash.new.tap do |mash|
139
158
  children.each do |c|
140
159
  mash[c.uid] ||= c.hrn
@@ -142,61 +161,78 @@ class OmfRc::ResourceProxy::AbstractResource
142
161
  end
143
162
  end
144
163
 
164
+ # Publish an inform message
165
+ # @param [Symbol] inform_type the type of inform message
166
+ # @param [Hash | Hashie::Mash | Exception | String] inform_data the type of inform message
167
+ def inform(inform_type, inform_data)
168
+ inform_data = Hashie::Mash.new(inform_data) if inform_data.class == Hash
169
+
170
+ case inform_type
171
+ when :failed
172
+ unless inform_data.kind_of? Exception
173
+ raise ArgumentError, "FAILED message requires an Exception (or MessageProcessError)"
174
+ end
175
+ when :created, :released
176
+ unless inform_data.respond_to?(:resource_id) && !inform_data.resource_id.nil?
177
+ raise ArgumentError, "CREATED or RELEASED message requires inform_data object respond to resource_id"
178
+ end
179
+ when :status
180
+ unless inform_data.respond_to?(:status) && inform_data.status.kind_of?(Hash)
181
+ raise ArgumentError, "STATUS message requires a hash represents properties"
182
+ end
183
+ end
184
+
185
+ context_id = inform_data.context_id if inform_data.respond_to? :context_id
186
+ inform_to = inform_data.inform_to if inform_data.respond_to? :inform_to
187
+ inform_to ||= self.uid
188
+
189
+ inform_message = OmfCommon::Message.inform(inform_type.to_s.upcase, context_id) do |i|
190
+ case inform_type
191
+ when :created
192
+ i.element('resource_id', inform_data.resource_id)
193
+ i.element('resource_address', inform_data.resource_id)
194
+ when :status
195
+ inform_data.status.each_pair { |k, v| i.property(k, v) }
196
+ when :released
197
+ i.element('resource_id', inform_data.resource_id)
198
+ when :error, :warn
199
+ i.element("reason", (inform_data.message rescue inform_data))
200
+ logger.__send__(inform_type, (inform_data.message rescue inform_data))
201
+ when :failed
202
+ i.element("reason", inform_data.message)
203
+ end
204
+ end
205
+ @comm.publish(inform_to, inform_message)
206
+ end
207
+
208
+ private
209
+
145
210
  # Parse omf message and execute as instructed by the message
146
211
  #
147
212
  def process_omf_message(pubsub_item_payload, topic)
148
213
  dp = OmfRc::DeferredProcess.new
149
214
 
150
- dp.callback do |end_result|
151
- if end_result
152
- case end_result[:operation]
153
- when :create
154
- new_uid = end_result[:result]
155
- @comm.create_topic(new_uid, host) do
156
- @comm.subscribe(new_uid, host) do
157
- inform_msg = OmfCommon::Message.inform(end_result[:context_id], 'CREATED') do |i|
158
- i.element('resource_id', new_uid)
159
- i.element('resource_address', new_uid)
160
- end
161
- @comm.publish(end_result[:inform_to], inform_msg, host)
162
- end
163
- end
164
- when :request
165
- inform_msg = OmfCommon::Message.inform(end_result[:context_id], 'STATUS') do |i|
166
- end_result[:result].each_pair do |k, v|
167
- i.property(k, v)
168
- end
169
- end
170
- @comm.publish(end_result[:inform_to], inform_msg, host)
171
-
172
- when :configure
173
- inform_msg = OmfCommon::Message.inform(end_result[:context_id], 'STATUS') do |i|
174
- end_result[:result].each_pair do |k, v|
175
- i.property(k, v)
176
- end
177
- end
178
- @comm.publish(end_result[:inform_to], inform_msg, host)
179
- when :release
180
- inform_msg = OmfCommon::Message.inform(end_result[:context_id], 'RELEASED') do |i|
181
- i.element('resource_id', end_result[:inform_to])
182
- end
183
-
184
- end_result[:result].each do |n|
185
- @comm.delete_topic(n, host)
186
- end
187
-
188
- EM.add_timer(RELEASE_WAIT) do
189
- @comm.publish(end_result[:inform_to], inform_msg, host)
215
+ dp.callback do |response|
216
+ response = Hashie::Mash.new(response)
217
+ case response.operation
218
+ when :create
219
+ new_uid = response.resource_id
220
+ @comm.create_topic(new_uid) do
221
+ @comm.subscribe(new_uid) do
222
+ inform(:created, response)
190
223
  end
191
224
  end
225
+ when :request, :configure
226
+ inform(:status, response)
227
+ when :release
228
+ EM.add_timer(RELEASE_WAIT) do
229
+ inform(:released, response)
230
+ end
192
231
  end
193
232
  end
194
233
 
195
234
  dp.errback do |e|
196
- inform_msg = OmfCommon::Message.inform(e.context_id, 'FAILED') do |i|
197
- i.element("error_message", e.message)
198
- end
199
- @comm.publish(e.inform_to, inform_msg, host)
235
+ inform(:failed, e)
200
236
  end
201
237
 
202
238
  dp.fire do
@@ -214,35 +250,33 @@ class OmfRc::ResourceProxy::AbstractResource
214
250
  create_opts = opts.dup
215
251
  create_opts.uid = nil
216
252
  result = obj.create(message.read_property(:type), create_opts)
217
- message.read_element("//property").each do |p|
253
+ message.each_property do |p|
218
254
  unless p.attr('key') == 'type'
219
255
  method_name = "configure_#{p.attr('key')}"
220
- result.send(method_name, p.content) if result.respond_to? method_name
256
+ result.__send__(method_name, message.read_property(p.attr('key')))
221
257
  end
222
258
  end
223
- { operation: :create, result: result.uid, context_id: context_id, inform_to: uid }
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 }
224
261
  when :request
225
262
  result = Hashie::Mash.new.tap do |mash|
226
263
  message.read_element("//property").each do |p|
227
264
  method_name = "request_#{p.attr('key')}"
228
- if obj.respond_to? method_name
229
- mash[p.attr('key')] ||= obj.send(method_name)
230
- end
265
+ mash[p.attr('key')] ||= obj.__send__(method_name, message.read_property(p.attr('key')))
231
266
  end
232
267
  end
233
- { operation: :request, result: result, context_id: context_id, inform_to: obj.uid }
268
+ { operation: :request, status: result, context_id: context_id, inform_to: obj.uid }
234
269
  when :configure
235
270
  result = Hashie::Mash.new.tap do |mash|
236
271
  message.read_element("//property").each do |p|
237
272
  method_name = "configure_#{p.attr('key')}"
238
- if obj.respond_to? method_name
239
- mash[p.attr('key')] ||= obj.send(method_name, p.content)
240
- end
273
+ mash[p.attr('key')] ||= obj.__send__(method_name, message.read_property(p.attr('key')))
241
274
  end
242
275
  end
243
- { operation: :configure, result: result, context_id: context_id, inform_to: obj.uid }
276
+ { operation: :configure, status: result, context_id: context_id, inform_to: obj.uid }
244
277
  when :release
245
- { operation: :release, result: obj.release, context_id: context_id, inform_to: obj.uid }
278
+ resource_id = message.resource_id
279
+ { operation: :release, resource_id: obj.release(resource_id).uid, context_id: context_id, inform_to: obj.uid }
246
280
  when :inform
247
281
  # We really don't care about inform messages which created from here
248
282
  nil
@@ -250,9 +284,16 @@ class OmfRc::ResourceProxy::AbstractResource
250
284
  raise "Unknown OMF operation #{message.operation}"
251
285
  end
252
286
  rescue => e
253
- logger.error e.message
254
- logger.error e.backtrace.join("\n")
255
- raise OmfRc::MessageProcessError.new(context_id, obj.uid, e.message)
287
+ if (e.kind_of? NoMethodError) && (message.operation == :configure || message.operation == :request)
288
+ msg = "Cannot #{message.operation} unknown property "+
289
+ "'#{message.read_element("//property")}' for resource '#{type}'"
290
+ logger.warn msg
291
+ raise OmfRc::MessageProcessError.new(context_id, obj.uid, msg)
292
+ else
293
+ logger.error e.message
294
+ logger.error e.backtrace.join("\n")
295
+ raise OmfRc::MessageProcessError.new(context_id, obj.uid, e.message)
296
+ end
256
297
  end
257
298
  end
258
299
  end