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
@@ -0,0 +1,471 @@
1
+ #
2
+ # Copyright (c) 2012 National ICT Australia (NICTA), Australia
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ #
23
+ # This module defines a Resource Proxy (RP) for a Generic Application
24
+ #
25
+ # Utility dependencies: platform_toos, common_tools
26
+ #
27
+ # This Generic Application Proxy has the following properties:
28
+ #
29
+ # - binary_path (String) the path to the binary of this app
30
+ # - pkg_tarball (String) the URI of the installation tarball of this app
31
+ # - pkg_ubuntu (String) the name of the Ubuntu package for this app
32
+ # - pkg_fedora (String) the name of the Fedora package for this app
33
+ # - state (String) the state of this Application RP
34
+ # (stop, run, pause, install)
35
+ # - installed (Boolean) is this application installed? (default false)
36
+ # - force_tarball_install (Boolean) if true then force the installation
37
+ # from tarball even if other distribution-specific
38
+ # installation are available (default false)
39
+ # - map_err_to_out (Boolean) if true then map StdErr to StdOut for this
40
+ # app (default false)
41
+ # - platform (Symbol) the OS platform where this app is running
42
+ #
43
+ # - environment (Hash) the environment variables to set prior to starting
44
+ # this app. {k1 => v1, ...} will result in "env -i K1=v1 ... "
45
+ # (with k1 being either a String or a Symbol)
46
+ #
47
+ # - parameters (Hash) the command line parameters available for this app.
48
+ # This hash is of the form: { :param1 => attribut1, ... }
49
+ # with param1 being the id of this parameter for this Proxy and
50
+ # with attribut1 being another Hash with the following possible
51
+ # keys and values (all are optional):
52
+ # :cmd (String) the command line for this parameter
53
+ # :order (Fixnum) the appearance order on the command line, default FIFO
54
+ # :dynamic (Boolean) parameter can be dynammically changed, default false
55
+ # :type (Numeric|String|Boolean) this parameter's type
56
+ # :default value given by default to this parameter
57
+ # :value value to set for this parameter
58
+ # :mandatory (Boolean) this parameter is mandatory, default false
59
+ #
60
+ # Two examples of valid parameters definition are:
61
+ #
62
+ # { :host => {:default => 'localhost', :type => 'String',
63
+ # :mandatory => true, :order => 2},
64
+ # :port => {:default => 5000, :type => 'Numeric', :cmd => '-p',
65
+ # :mandatory => true, :order => 1},
66
+ # :size => {:default => 512, :type => 'Numeric', :cmd => '--pkt-size',
67
+ # :mandatory => true, :dynamic => true}
68
+ # :title => {:type => 'String', :mandatory => false}
69
+ # }
70
+ #
71
+ # and
72
+ #
73
+ # { :title => {:value => "My First Application"} }
74
+ #
75
+ module OmfRc::ResourceProxy::GenericApplication
76
+ include OmfRc::ResourceProxyDSL
77
+ require 'omf_common/exec_app'
78
+
79
+ register_proxy :generic_application
80
+ utility :platform_tools
81
+ utility :common_tools
82
+
83
+ MAX_PARAMETER_NUMBER = 1000
84
+ DEFAULT_MANDATORY_PARAMETER = false
85
+
86
+ hook :before_ready do |res|
87
+ res.property.app_id ||= nil
88
+ res.property.binary_path ||= nil
89
+ res.property.platform ||= nil
90
+ res.property.pkg_tarball ||= nil
91
+ res.property.tarball_install_path ||= '/'
92
+ res.property.force_tarball_install ||= false
93
+ res.property.pkg_ubuntu ||= nil
94
+ res.property.pkg_fedora ||= nil
95
+ res.property.state ||= :stop
96
+ res.property.installed ||= false
97
+ res.property.map_err_to_out ||= false
98
+ res.property.event_sequence ||= 0
99
+ res.property.parameters ||= Hash.new
100
+ res.property.environments ||= Hash.new
101
+ define_method("on_app_event") { |*args| process_event(self, *args) }
102
+ end
103
+
104
+ # This method processes an event coming from the application instance, which
105
+ # was started by this Resource Proxy (RP). It is a callback, which is usually
106
+ # called by the ExecApp class in OMF
107
+ #
108
+ # @param [AbstractResource] res this RP
109
+ # @param [String] event_type the type of event from the app instance
110
+ # (STARTED, DONE.OK, DONE.ERROR, STDOUT, STDERR)
111
+ # @param [String] app_id the id of the app instance
112
+ # @param [String] msg the message carried by the event
113
+ #
114
+ def process_event(res, event_type, app_id, msg)
115
+ logger.info "App Event from '#{app_id}' "+
116
+ "(##{res.property.event_sequence}) - "+
117
+ "#{event_type}: '#{msg}'"
118
+ res.property.state = :stop if event_type.to_s.include?('DONE')
119
+ res.comm.publish(res.uid,
120
+ OmfCommon::Message.inform('STATUS') do |message|
121
+ message.property('status_type' , 'APP_EVENT')
122
+ message.property('event' , event_type.to_s.upcase)
123
+ message.property('app' , app_id)
124
+ message.property('msg' , "#{msg}")
125
+ message.property('seq' , "#{res.property.event_sequence}")
126
+ end)
127
+ res.property.event_sequence += 1
128
+ res.property.installed = true if app_id.include?("_INSTALL") &&
129
+ event_type.to_s.include?('DONE.OK')
130
+ end
131
+
132
+ # Request the basic properties of this Generic Application RP.
133
+ # @see OmfRc::ResourceProxy::GenericApplication
134
+ #
135
+ %w(binary_path pkg_tarball pkg_ubuntu pkg_fedora state installed \
136
+ force_tarball_install map_err_to_out tarball_install_path).each do |prop|
137
+ request(prop) { |res| res.property[prop].to_s }
138
+ end
139
+
140
+ # Request the platform property of this Generic Application RP
141
+ # @see OmfRc::ResourceProxy::GenericApplication
142
+ #
143
+ request :platform do |res|
144
+ res.property.platform = detect_platform if res.property.platform.nil?
145
+ res.property.platform.to_s
146
+ end
147
+
148
+ # Configure the basic properties of this Generic Application RP
149
+ # @see OmfRc::ResourceProxy::GenericApplication
150
+ #
151
+ %w(binary_path pkg_tarball pkg_ubuntu pkg_fedora force_tarball_install \
152
+ map_err_to_out tarball_install_path).each do |prop|
153
+ configure(prop) { |res, value| res.property[prop] = value }
154
+ end
155
+
156
+ # Configure the environments property of this Generic Application RP
157
+ # @see OmfRc::ResourceProxy::GenericApplication
158
+ #
159
+ configure :environments do |res, envs|
160
+ if envs.kind_of? Hash
161
+ res.property.environments = res.property.environments.merge(envs)
162
+ else
163
+ res.log_inform_error "Environment configuration failed! "+
164
+ "Environments not passed as Hash (#{envs.inspect})"
165
+ end
166
+ res.property.environments
167
+ end
168
+
169
+ # Configure the parameters property of this Generic Application RP
170
+ # @see OmfRc::ResourceProxy::GenericApplication
171
+ #
172
+ configure :parameters do |res, params|
173
+ if params.kind_of? Hash
174
+ params.each do |p,v|
175
+ if v.kind_of? Hash
176
+ # if this param has no set order, then assign the highest number to it
177
+ # this will allow sorting the parameters later
178
+ v[:order] = MAX_PARAMETER_NUMBER if v[:order].nil?
179
+ # if this param has no set mandatory field, assign it a default one
180
+ v[:mandatory] = DEFAULT_MANDATORY_PARAMETER if v[:mandatory].nil?
181
+ merged_val = res.property.parameters[p].nil? ? v : res.property.parameters[p].merge(v)
182
+ new_val = res.sanitize_parameter(p,merged_val)
183
+ # only set this new parameter if it passes the type check
184
+ if res.pass_type_checking?(new_val)
185
+ res.property.parameters[p] = new_val
186
+ res.dynamic_parameter_update(p,new_val)
187
+ else
188
+ res.log_inform_error "Configuration of parameter '#{p}' failed "+
189
+ "type checking. Defined type is #{new_val[:type]} while assigned "+
190
+ "value/default are #{new_val[:value].inspect} / "+
191
+ "#{new_val[:default].inspect}"
192
+ end
193
+ else
194
+ res.log_inform_error "Configuration of parameter '#{p}' failed!"+
195
+ "Options not passed as Hash (#{v.inspect})"
196
+ end
197
+ end
198
+ else
199
+ res.log_inform_error "Parameter configuration failed! Parameters not "+
200
+ "passed as Hash (#{params.inspect})"
201
+ end
202
+ res.property.parameters[p]
203
+ end
204
+
205
+ # Configure the state of this Generic Application RP. The valid states are
206
+ # stop, run, pause, install. The semantic of each states are:
207
+ #
208
+ # - stop: the initial state for an Application RP, and the final state for
209
+ # an applicaiton RP, for which the application instance finished
210
+ # its execution or its installation
211
+ # - run: upon entering in this state, a new instance of the application is
212
+ # started, the Application RP stays in this state until the
213
+ # application instance is finished or paused. The Application RP can
214
+ # only enter this state from a previous 'pause' or 'stop' state.
215
+ # - pause: upon entering this state, the currently running instance of this
216
+ # application should be paused (it is the responsibility of
217
+ # specialised Application Proxy to ensure that! The default Generic
218
+ # Application Proxy does nothing to the application instance when
219
+ # entering this state). The Application RP can only enter this
220
+ # state from a previous 'run' state.
221
+ # - install: upon entering in this state, a new installation of the
222
+ # application will be performed by the Application RP, which will
223
+ # stay in this state until the installation is finished. The
224
+ # Application RP can only enter this state from a previous 'stop'
225
+ # state, and can only enter a 'stop' state once the installation
226
+ # is finished.
227
+ # Supported install methods are: Tarball, Ubuntu, and Fedora
228
+ #
229
+ # @yieldparam [String] value the state to set this app into
230
+ #
231
+ configure :state do |res, value|
232
+ case value.to_s.downcase.to_sym
233
+ when :install then res.switch_to_install
234
+ when :stop then res.switch_to_stop
235
+ when :run then res.switch_to_run
236
+ when :pause then res.switch_to_pause
237
+ end
238
+ res.property.state
239
+ end
240
+
241
+ # Swich this Application RP into the 'install' state
242
+ # (see the description of configure :state)
243
+ #
244
+ work('switch_to_install') do |res|
245
+ if res.property.state.to_sym == :stop
246
+ if res.property.installed
247
+ res.log_inform_warn "The application is already installed"
248
+ else
249
+ # Select the proper installation method based on the platform
250
+ # and the value of 'force_tarball_install'
251
+ res.property.state = :install
252
+ if res.property.force_tarball_install ||
253
+ (res.property.platform == :unknown)
254
+ installing = res.install_tarball(res.property.pkg_tarball,
255
+ res.property.tarball_install_path)
256
+ elsif res.property.platform == :ubuntu
257
+ installing = res.install_ubuntu(res.property.pkg_ubuntu)
258
+ elsif res.property.platform == :fedora
259
+ installing = res.install_fedora(res.property.pkg_fedora)
260
+ end
261
+ res.property.state = :stop unless installing
262
+ end
263
+ else
264
+ # cannot install as we are not stopped
265
+ res.log_inform_warn "Not in STOP state. Cannot switch to INSTALL state!"
266
+ end
267
+ end
268
+
269
+ # Swich this Application RP into the 'stop' state
270
+ # (see the description of configure :state)
271
+ #
272
+ work('switch_to_stop') do |res|
273
+ if res.property.state == :run || res.property.state == :pause
274
+ id = res.property.app_id
275
+ unless ExecApp[id].nil?
276
+ # stop this app
277
+ begin
278
+ # first, try sending 'exit' on the stdin of the app, and wait
279
+ # for 4s to see if the app acted on it...
280
+ ExecApp[id].stdin('exit')
281
+ sleep 4
282
+ unless ExecApp[id].nil?
283
+ # second, try sending TERM signal, wait another 4s to see
284
+ # if the app acted on it...
285
+ ExecApp[id].signal('TERM')
286
+ sleep 4
287
+ # finally, try sending KILL signal
288
+ ExecApp[id].kill('KILL') unless ExecApp[id].nil?
289
+ end
290
+ res.property.state = :stop
291
+ rescue => err
292
+ end
293
+ end
294
+ end
295
+ end
296
+
297
+ # Swich this Application RP into the 'run' state
298
+ # (see the description of configure :state)
299
+ #
300
+ work('switch_to_run') do |res|
301
+ if res.property.state == :stop
302
+ # start a new instance of this app
303
+ res.property.app_id = res.hrn.nil? ? res.uid : res.hrn
304
+ # we need at least a defined binary path to run an app...
305
+ if res.property.binary_path.nil?
306
+ res.log_inform_warn "Binary path not set! No Application to run!"
307
+ else
308
+ ExecApp.new(res.property.app_id, res,
309
+ res.build_command_line,
310
+ res.property.map_err_to_out)
311
+ res.property.state = :run
312
+ end
313
+ elsif res.property.state == :pause
314
+ # resume this paused app
315
+ res.property.state = :run
316
+ # do more things here...
317
+ elsif res.property.state == :install
318
+ # cannot run as we are still installing
319
+ res.log_inform_warn "Still in INSTALL state. Cannot switch to RUN state!"
320
+ end
321
+ end
322
+
323
+ # Swich this Application RP into the 'pause' state
324
+ # (see the description of configure :state)
325
+ #
326
+ work('switch_to_pause') do |res|
327
+ if res.property.state == :run
328
+ # pause this app
329
+ res.property.state = :pause
330
+ # do more things here...
331
+ end
332
+ end
333
+
334
+ # Check if a parameter is dynamic, and if so update its value if the
335
+ # application is currently running
336
+ #
337
+ # @yieldparam [String] name the parameter id as known by this app
338
+ # @yieldparam [Hash] att the Hash holding the parameter's attributs
339
+ # @see OmfRc::ResourceProxy::GenericApplication
340
+ #
341
+ work('dynamic_parameter_update') do |res,name,att|
342
+ # Only update a parameter if it is dynamic and the application is running
343
+ dynamic = false
344
+ dynamic = att[:dynamic] if res.boolean?(att[:dynamic])
345
+ if dynamic && res.property.state == :run
346
+ line = ""
347
+ line += "#{att[:cmd]} " unless att[:cmd].nil?
348
+ line += "#{att[:value]}"
349
+ ExecApp[res.property.app_id].stdin(line)
350
+ logger.info "Updated parameter #{name} with value #{att[:value].inspect}"
351
+ end
352
+ end
353
+
354
+ # First, convert any 'true' or 'false' strings from the :mandatory and
355
+ # :dynamic attributs of a given parameter into TrueClass or FalseClass
356
+ # instances.
357
+ # Second, if that parameter is of a type Boolean, then perform the same
358
+ # conversion on the assigned default and value of this parameter
359
+ #
360
+ # @yieldparam [String] name the parameter id as known by this app
361
+ # @yieldparam [Hash] att the Hash holding the parameter's attributs
362
+ #
363
+ # [Hash] a copy of the input Hash with the above conversion performed in it
364
+ #
365
+ work('sanitize_parameter') do |res,name,att|
366
+ begin
367
+ if !att[:mandatory].nil? && !res.boolean?(att[:mandatory])
368
+ att[:mandatory] = eval(att[:mandatory].downcase)
369
+ end
370
+ if !att[:dynamic].nil? && !res.boolean?(att[:dynamic])
371
+ att[:dynamic] = eval(att[:dynamic].downcase)
372
+ end
373
+ if (att[:type] == 'Boolean')
374
+ att[:value] = eval(att[:value].downcase) if !att[:value].nil? && !res.boolean?(att[:value])
375
+ att[:default] = eval(att[:default].downcase) if !att[:default].nil? && !res.boolean?(att[:default])
376
+ end
377
+ rescue Exception => ex
378
+ res.log_inform_error "Cannot sanitize the parameter '#{name}' (#{att.inspect})"
379
+ end
380
+ att
381
+ end
382
+
383
+ # Check if a requested value or default for a parameter has the same
384
+ # type as the type defined for that parameter
385
+ # The checking procedure is as follows:
386
+ # - first check if a type was set for this parameter, if not then return true
387
+ # Thus if no type was defined for this parameter then return true
388
+ # regardless of the type of the given value or default
389
+ # - second check if a value is given, if so check if it has the same type as
390
+ # the defined type, if so then return true, if not then return false.
391
+ # - third if no value is given but a default is given, then perform the same
392
+ # check as above but using the default in-place of the value
393
+ #
394
+ # @yieldparam [Hash] att the Hash holding the parameter's attributs
395
+ #
396
+ # [Boolean] true or false
397
+ #
398
+ work('pass_type_checking?') do |res,att|
399
+ passed = false
400
+ unless att[:type].nil?
401
+ if att[:type] == 'Boolean' # HACK: as Ruby does not have a Boolean type
402
+ if !att[:default].nil? && !att[:value].nil?
403
+ passed = true if res.boolean?(att[:default]) && res.boolean?(att[:value])
404
+ elsif att[:default].nil? && att[:value].nil?
405
+ passed = true
406
+ elsif att[:default].nil?
407
+ passed = true if res.boolean?(att[:value])
408
+ elsif att[:value].nil?
409
+ passed = true if res.boolean?(att[:default])
410
+ end
411
+ else # HACK: Now for all other types...
412
+ klass = Module.const_get(att[:type].capitalize.to_sym)
413
+ if !att[:default].nil? && !att[:value].nil?
414
+ passed = true if att[:default].kind_of?(klass) && att[:value].kind_of?(klass)
415
+ elsif att[:default].nil? && att[:value].nil?
416
+ passed = true
417
+ elsif att[:default].nil?
418
+ passed = true if att[:value].kind_of?(klass)
419
+ elsif att[:value].nil?
420
+ passed = true if att[:default].kind_of?(klass)
421
+ end
422
+ end
423
+ else
424
+ passed = true
425
+ end
426
+ passed
427
+ end
428
+
429
+ # Build the command line, which will be used to start this app
430
+ # This command line will be of the form:
431
+ # "env -i VAR1=value1 ... application_path parameterA valueA ..."
432
+ #
433
+ # The environment variables and the parameters in that command line are
434
+ # taken respectively from the 'environments' and 'parameters' properties of
435
+ # this Generic Application Resource Proxy.
436
+ #
437
+ # [String] the full command line
438
+ #
439
+ work('build_command_line') do |res|
440
+ cmd_line = "env -i " # Start with a 'clean' environments
441
+ res.property.environments.each do |e,v|
442
+ val = v.kind_of?(String) ? "'#{v}'" : v
443
+ cmd_line += "#{e.to_s.upcase}=#{val} "
444
+ end
445
+ cmd_line += res.property.binary_path + " "
446
+ # Add command line parameter in their specified order if any
447
+ sorted_parameters = res.property.parameters.sort_by {|k,v| v[:order]}
448
+ sorted_parameters.each do |param,att|
449
+ needed = false
450
+ needed = att[:mandatory] if res.boolean?(att[:mandatory])
451
+ # For mandatory parameter without a value, take the default one
452
+ val = att[:value]
453
+ val = att[:default] if needed && att[:value].nil?
454
+ # Finally add the parameter if is value/default is not nil
455
+ unless val.nil?
456
+ if att[:type] == "Boolean"
457
+ # for Boolean param, only the command is printed if value==true
458
+ cmd_line += "#{att[:cmd]} " if val == true
459
+ else
460
+ # for all other type of param, we print "cmd value"
461
+ # with a user-provided prefix/suffix if defined
462
+ cmd_line += "#{att[:cmd]} "
463
+ cmd_line += att[:prefix].nil? ? "#{val}" : "#{att[:prefix]}#{val}"
464
+ cmd_line += att[:suffix].nil? ? " " : "#{att[:suffix]} "
465
+ end
466
+ end
467
+ end
468
+ cmd_line
469
+ end
470
+
471
+ end
@@ -0,0 +1,7 @@
1
+ module OmfRc::ResourceProxy::Net
2
+ include OmfRc::ResourceProxyDSL
3
+
4
+ register_proxy :net
5
+
6
+ utility :ip
7
+ end
@@ -3,15 +3,41 @@ module OmfRc::ResourceProxy::Node
3
3
 
4
4
  register_proxy :node
5
5
 
6
- hook :before_ready do |resource|
7
- logger.info "#{resource.uid} is now ready"
6
+ request :proxies do
7
+ OmfRc::ResourceFactory.proxy_list
8
8
  end
9
9
 
10
- hook :before_release do |resource|
11
- logger.info "#{resource.uid} is now released"
12
- end
10
+ request :devices do |resource|
11
+ devices = []
12
+ Dir.chdir("/sys/class") do
13
+ # Support net devices for now
14
+ category = "net"
13
15
 
14
- request :proxies do
15
- OmfRc::ResourceFactory.proxy_list
16
+ Dir.glob("net/eth*").each do |v|
17
+ File.exist?("#{v}/uevent") && File.open("#{v}/uevent") do |f|
18
+ subcategory = f.read.match(/DEVTYPE=(.+)/) && $1
19
+ proxy = "net"
20
+ File.exist?("#{v}/device/uevent") && File.open("#{v}/device/uevent") do |f|
21
+ driver = f.read.match(/DRIVER=(.+)/) && $1
22
+ device = { name: File.basename(v), driver: driver, category: category }
23
+ device[:subcategory] = subcategory if subcategory
24
+ device[:proxy] = proxy if resource.request_proxies.include?(proxy.to_sym)
25
+ devices << device
26
+ end
27
+ end
28
+ end
29
+
30
+ Dir.glob("ieee80211/*").each do |v|
31
+ subcategory = "wlan"
32
+ proxy = "wlan"
33
+ File.exist?("#{v}/device/uevent") && File.open("#{v}/device/uevent") do |f|
34
+ driver = f.read.match(/DRIVER=(.+)/) && $1
35
+ device = { name: File.basename(v), driver: driver, category: category, subcategory: subcategory }
36
+ device[:proxy] = proxy if resource.request_proxies.include?(proxy.to_sym)
37
+ devices << device
38
+ end
39
+ end
40
+ end
41
+ devices
16
42
  end
17
43
  end
@@ -0,0 +1,79 @@
1
+ # This resource is created from the parent :openflow_slice_factory resource.
2
+ # It is related with a slice of a flowvisor instance, and behaves as a proxy between experimenter and the actual flowvisor slice.
3
+ #
4
+ module OmfRc::ResourceProxy::OpenflowSlice
5
+ include OmfRc::ResourceProxyDSL
6
+
7
+ # The default parameters of a new slice. The openflow controller is assumed to be in the same working station with flowvisor instance
8
+ SLICE_DEFAULTS = {
9
+ passwd: "1234",
10
+ url: "tcp:127.0.0.1:9933",
11
+ email: "nothing@nowhere"
12
+ }
13
+
14
+
15
+ register_proxy :openflow_slice
16
+
17
+ utility :openflow_tools
18
+
19
+
20
+ # Slice's name is initiated with value "nil"
21
+ hook :before_ready do |resource|
22
+ resource.property.name = nil
23
+ end
24
+
25
+ # Before release, the related flowvisor instance should also remove the corresponding slice
26
+ hook :before_release do |resource|
27
+ resource.flowvisor_connection.call("api.deleteSlice", resource.property.name)
28
+ end
29
+
30
+
31
+ # The name is one-time configured
32
+ configure :name do |resource, name|
33
+ raise "The name cannot be changed" if resource.property.name
34
+ resource.property.name = name.to_s
35
+ begin
36
+ resource.flowvisor_connection.call("api.createSlice", name.to_s, *SLICE_DEFAULTS.values)
37
+ rescue Exception => e
38
+ if e.message["Cannot create slice with existing name"]
39
+ logger.warn message = "The requested slice already existed in Flowvisor"
40
+ else
41
+ raise e
42
+ end
43
+ end
44
+ resource.property.name
45
+ end
46
+
47
+ # Configures the slice password
48
+ configure :passwd do |resource, passwd|
49
+ resource.flowvisor_connection.call("api.changePasswd", resource.property.name, passwd.to_s)
50
+ passwd.to_s
51
+ end
52
+
53
+ # Configures the slice parameters
54
+ [:contact_email, :drop_policy, :controller_hostname, :controller_port].each do |configure_sym|
55
+ configure configure_sym do |resource, value|
56
+ resource.flowvisor_connection.call("api.changeSlice", resource.property.name, configure_sym.to_s, value.to_s)
57
+ value.to_s
58
+ end
59
+ end
60
+
61
+ # Adds/removes a flow to this slice, specified by device, port, etc.
62
+ configure :flows do |resource, parameters|
63
+ resource.flowvisor_connection.call("api.changeFlowSpace", resource.transformed_parameters(parameters))
64
+ resource.flows
65
+ end
66
+
67
+
68
+ # Returns a hash table with the name of this slice, its controller (ip and port) and other related information
69
+ request :info do |resource|
70
+ result = resource.flowvisor_connection.call("api.getSliceInfo", resource.property.name)
71
+ result[:name] = resource.property.name
72
+ result
73
+ end
74
+
75
+ # Returns a string with statistics about the use of this slice
76
+ request :stats do |resource|
77
+ resource.flowvisor_connection.call("api.getSliceStats", resource.property.name)
78
+ end
79
+ end
@@ -0,0 +1,71 @@
1
+ # This resourse is related with a flowvisor instance and behaves as a proxy between experimenter and flowvisor.
2
+ #
3
+ module OmfRc::ResourceProxy::OpenflowSliceFactory
4
+ include OmfRc::ResourceProxyDSL
5
+
6
+ # The default arguments of the communication between this resource and the flowvisor instance
7
+ FLOWVISOR_CONNECTION_DEFAULTS = {
8
+ host: "localhost",
9
+ path: "/xmlrc",
10
+ port: "8080",
11
+ proxy_host: nil,
12
+ proxy_port: nil,
13
+ user: "fvadmin",
14
+ password: "openflow",
15
+ use_ssl: "true",
16
+ timeout: nil
17
+ }
18
+
19
+
20
+ register_proxy :openflow_slice_factory
21
+
22
+ utility :openflow_tools
23
+
24
+
25
+ # Checks if the created child is an :openflow_slice resource and passes the connection arguments that are essential for the connection with flowvisor instance
26
+ hook :before_create do |resource, type, opts = nil|
27
+ if type.to_sym != :openflow_slice
28
+ raise "This resource doesn't create resources of type "+type
29
+ end
30
+ begin
31
+ resource.flowvisor_connection
32
+ rescue
33
+ raise "This resource is not connected with a flowvisor instance, so it cannot create openflow slices"
34
+ end
35
+ opts.property ||= Hashie::Mash.new
36
+ opts.property.flowvisor_connection_args = resource.property.flowvisor_connection_args
37
+ end
38
+
39
+
40
+ # A new resource uses the default connection arguments (ip adress, port, etc) to connect with a flowvisor instance
41
+ hook :before_ready do |resource|
42
+ resource.property.flowvisor_connection_args = FLOWVISOR_CONNECTION_DEFAULTS
43
+ end
44
+
45
+
46
+ # Configures the flowvisor connection arguments (ip adress, port, etc)
47
+ configure :flowvisor_connection do |resource, flowvisor_connection_args|
48
+ raise "Connection with a new flowvisor instance is not allowed if there exist created slices" if !resource.children.empty?
49
+ resource.property.flowvisor_connection_args.update(flowvisor_connection_args)
50
+ end
51
+
52
+
53
+ # Returns the flowvisor connection arguments (ip adress, port, etc)
54
+ request :flowvisor_connection do |resource|
55
+ resource.property.flowvisor_connection_args
56
+ end
57
+
58
+ # Returns a list of the existed slices or the connected devices
59
+ {:slices => "listSlices", :devices => "listDevices"}.each do |request_sym, handler_name|
60
+ request request_sym do |resource|
61
+ resource.flowvisor_connection.call("api.#{handler_name}")
62
+ end
63
+ end
64
+
65
+ # Returns information or statistics for a device specified by the given id
66
+ {:device_info => "getDeviceInfo", :device_stats => "getSwitchStats"}.each do |request_sym, handler_name|
67
+ request request_sym do |resource, device|
68
+ resource.flowvisor_connection.call("api.#{handler_name}", device.to_s)
69
+ end
70
+ end
71
+ end