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

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