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.
- data/Rakefile +0 -6
- data/bin/omf_rc +2 -2
- data/lib/omf_rc/resource_factory.rb +10 -4
- data/lib/omf_rc/resource_proxy/abstract_resource.rb +120 -79
- data/lib/omf_rc/resource_proxy/generic_application.rb +471 -0
- data/lib/omf_rc/resource_proxy/net.rb +7 -0
- data/lib/omf_rc/resource_proxy/node.rb +33 -7
- data/lib/omf_rc/resource_proxy/openflow_slice.rb +79 -0
- data/lib/omf_rc/resource_proxy/openflow_slice_factory.rb +71 -0
- data/lib/omf_rc/resource_proxy/wlan.rb +20 -0
- data/lib/omf_rc/resource_proxy_dsl.rb +142 -8
- data/lib/omf_rc/util/common_tools.rb +61 -0
- data/lib/omf_rc/util/hostapd.rb +52 -0
- data/lib/omf_rc/util/ip.rb +28 -0
- data/lib/omf_rc/util/iw.rb +119 -6
- data/lib/omf_rc/util/mock.rb +2 -1
- data/lib/omf_rc/util/openflow_tools.rb +103 -0
- data/lib/omf_rc/util/platform_tools.rb +164 -0
- data/lib/omf_rc/util/wpa.rb +42 -0
- data/lib/omf_rc/version.rb +1 -1
- data/omf_rc.gemspec +3 -1
- data/test/fixture/ip/addr_show +5 -0
- data/test/fixture/iw/info +4 -0
- data/test/fixture/sys/class/ieee80211/phy0/device/uevent +6 -0
- data/test/fixture/sys/class/ieee80211/phy0/uevent +0 -0
- data/test/fixture/sys/class/net/eth0/device/uevent +6 -0
- data/test/fixture/sys/class/net/eth0/uevent +2 -0
- data/test/fixture/sys/class/net/wlan0/device/uevent +6 -0
- data/test/fixture/sys/class/net/wlan0/uevent +3 -0
- data/test/omf_rc/message_process_error_spec.rb +11 -0
- data/test/omf_rc/resource_factory_spec.rb +8 -1
- data/test/omf_rc/resource_proxy/abstract_resource_spec.rb +57 -1
- data/test/omf_rc/resource_proxy/generic_application_spec.rb +347 -0
- data/test/omf_rc/resource_proxy/mock_spec.rb +15 -0
- data/test/omf_rc/resource_proxy/node_spec.rb +32 -1
- data/test/omf_rc/resource_proxy_dsl_spec.rb +81 -10
- data/test/omf_rc/util/common_tools_spec.rb +30 -0
- data/test/omf_rc/util/ip_spec.rb +51 -0
- data/test/omf_rc/util/iw_spec.rb +136 -25
- data/test/omf_rc/util/mock_spec.rb +26 -0
- data/test/omf_rc/util/mod_spec.rb +8 -11
- data/test/test_helper.rb +11 -0
- metadata +62 -6
- data/lib/omf_rc/resource_proxy/wifi.rb +0 -8
- data/test/mock_helper.rb +0 -15
@@ -0,0 +1,20 @@
|
|
1
|
+
module OmfRc::ResourceProxy::Wlan
|
2
|
+
include OmfRc::ResourceProxyDSL
|
3
|
+
|
4
|
+
register_proxy :wlan
|
5
|
+
|
6
|
+
utility :ip
|
7
|
+
utility :mod
|
8
|
+
utility :iw
|
9
|
+
|
10
|
+
hook :before_release do |device|
|
11
|
+
case device.property.mode.to_sym
|
12
|
+
when :master
|
13
|
+
device.stop_hostapd
|
14
|
+
when :managed
|
15
|
+
device.stop_wpa
|
16
|
+
end
|
17
|
+
#TODO need to remove all virtual interfaces of that phy device
|
18
|
+
#device.remove_all_interfaces
|
19
|
+
end
|
20
|
+
end
|
@@ -14,6 +14,9 @@ module OmfRc::ResourceProxyDSL
|
|
14
14
|
# Register a named proxy entry with factory class, normally this should be done in the proxy module
|
15
15
|
#
|
16
16
|
# @param [Symbol] name of the resource proxy
|
17
|
+
# @param [Hash] opts options to be passed to proxy registration
|
18
|
+
# @option opts [String, Array] :create_by resource can only be created by these resources.
|
19
|
+
#
|
17
20
|
# @example suppose we define a module for wifi
|
18
21
|
#
|
19
22
|
# module OmfRc::ResourceProxy::Wifi
|
@@ -21,19 +24,26 @@ module OmfRc::ResourceProxyDSL
|
|
21
24
|
#
|
22
25
|
# # Let the factory know it is available
|
23
26
|
# register_proxy :wifi
|
27
|
+
#
|
28
|
+
# # or use option :create_by
|
29
|
+
# register_proxy :wifi, :create_by => :node
|
24
30
|
# end
|
25
31
|
#
|
26
|
-
def register_proxy(name)
|
32
|
+
def register_proxy(name, opts = {})
|
27
33
|
name = name.to_sym
|
28
|
-
|
34
|
+
if opts[:create_by] && !opts[:create_by].kind_of?(Array)
|
35
|
+
opts[:create_by] = [opts[:create_by]]
|
36
|
+
end
|
37
|
+
OmfRc::ResourceFactory.register_proxy(name => opts)
|
29
38
|
end
|
30
39
|
|
31
40
|
# Register some hooks which can be called at certain stage of the operation
|
32
41
|
#
|
33
|
-
# Currently the system supports
|
42
|
+
# Currently the system supports these hooks:
|
34
43
|
#
|
35
44
|
# * before_ready, called when a resource created, before creating an associated pubsub topic
|
36
45
|
# * before_release, called before a resource released
|
46
|
+
# * before_create, called before parent creates the child resource. (in the context of parent resource)
|
37
47
|
#
|
38
48
|
# @param [Symbol] name hook name. :before_create or :before_release
|
39
49
|
# @yieldparam [AbstractResource] resource pass the current resource object to the block
|
@@ -44,6 +54,26 @@ module OmfRc::ResourceProxyDSL
|
|
44
54
|
#
|
45
55
|
# register_proxy :node
|
46
56
|
#
|
57
|
+
# # before_create hook
|
58
|
+
# #
|
59
|
+
# # the optional block will have access to three variables:
|
60
|
+
# # * resource: the parent resource itself
|
61
|
+
# # * new_resource_type: a string or symbol represents the new resource to be created
|
62
|
+
# # * new_resource_options: the options hash to be passed to the new resource
|
63
|
+
# #
|
64
|
+
# # this hook enable us to do things like:
|
65
|
+
# # * validating child resources: e.g. if parent could create this new resource
|
66
|
+
# # * setting up default child properties based on parent's property value
|
67
|
+
# hook :before_create do |resource, new_resource_type, new_resource_options|
|
68
|
+
# if new_resource_type.to_sym == :wifi
|
69
|
+
# logger.info "Resource type wifi is allowed"
|
70
|
+
# else
|
71
|
+
# raise "Go away, I can't create #{new_resource_type}"
|
72
|
+
# end
|
73
|
+
# new_resource_options.property ||= Hashie::Mash.new
|
74
|
+
# new_resource_options.property.node_info = "Node #{resource.uid}"
|
75
|
+
# end
|
76
|
+
#
|
47
77
|
# hook :before_ready do |resource|
|
48
78
|
# logger.info "#{resource.uid} is now ready"
|
49
79
|
# end
|
@@ -53,8 +83,8 @@ module OmfRc::ResourceProxyDSL
|
|
53
83
|
# end
|
54
84
|
# end
|
55
85
|
def hook(name, ®ister_block)
|
56
|
-
define_method(name) do
|
57
|
-
register_block.call(self) if register_block
|
86
|
+
define_method(name) do |*args, &block|
|
87
|
+
register_block.call(self, *args, block) if register_block
|
58
88
|
end
|
59
89
|
end
|
60
90
|
|
@@ -76,11 +106,13 @@ module OmfRc::ResourceProxyDSL
|
|
76
106
|
begin
|
77
107
|
# In case of module defined inline
|
78
108
|
include "OmfRc::Util::#{name.camelize}".constantize
|
109
|
+
extend "OmfRc::Util::#{name.camelize}".constantize
|
79
110
|
rescue NameError
|
80
111
|
begin
|
81
112
|
# Then we try to require the file and include the module
|
82
113
|
require "#{UTIL_DIR}/#{name}"
|
83
114
|
include "OmfRc::Util::#{name.camelize}".constantize
|
115
|
+
extend "OmfRc::Util::#{name.camelize}".constantize
|
84
116
|
rescue LoadError => le
|
85
117
|
logger.error le.message
|
86
118
|
rescue NameError => ne
|
@@ -122,7 +154,8 @@ module OmfRc::ResourceProxyDSL
|
|
122
154
|
#
|
123
155
|
def configure(name, ®ister_block)
|
124
156
|
define_method("configure_#{name.to_s}") do |*args, &block|
|
125
|
-
|
157
|
+
args[0] = Hashie::Mash.new(args[0]) if args[0].class == Hash
|
158
|
+
register_block.call(self, *args, block) if register_block
|
126
159
|
end
|
127
160
|
end
|
128
161
|
|
@@ -146,9 +179,110 @@ module OmfRc::ResourceProxyDSL
|
|
146
179
|
# end
|
147
180
|
# end
|
148
181
|
def request(name, ®ister_block)
|
149
|
-
define_method("request_#{name.to_s}") do |*args|
|
150
|
-
|
182
|
+
define_method("request_#{name.to_s}") do |*args, &block|
|
183
|
+
args[0] = Hashie::Mash.new(args[0]) if args[0].class == Hash
|
184
|
+
register_block.call(self, *args, block) if register_block
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# Define an arbitrary method to do some work, can be included in configure & request block
|
189
|
+
#
|
190
|
+
# @param (see #configure)
|
191
|
+
# @yieldparam [AbstractResource] resource pass the current resource object to the block
|
192
|
+
# @example suppose we define a simple os checking method
|
193
|
+
#
|
194
|
+
# work :os do
|
195
|
+
# Command.execute("uname")
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
# # then this os method will be available in all proxy definitions which includes this work method definition.
|
199
|
+
# # if for some reason you need to call 'os' method within the same module, you need to access it via the resource instance.
|
200
|
+
#
|
201
|
+
# work :install_software do |resource|
|
202
|
+
# raise 'Can not support non-linux distro yet' if resource.os == 'Linux'
|
203
|
+
# end
|
204
|
+
def work(name, ®ister_block)
|
205
|
+
define_method(name) do |*args, &block|
|
206
|
+
register_block.call(self, *args, block) if register_block
|
151
207
|
end
|
152
208
|
end
|
209
|
+
|
210
|
+
# Extend existing hook definition by alias existing method name as "orig_[method_name]"
|
211
|
+
#
|
212
|
+
# @param [#to_s] hook_name name of existing hook
|
213
|
+
# @example extend a hook definition
|
214
|
+
#
|
215
|
+
# # suppose existing hook defined as this:
|
216
|
+
# hook :before_ready do |resource|
|
217
|
+
# logger.info "I am ready"
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# # now in a new proxy where we want to extend this hook, add more functionality:
|
221
|
+
#
|
222
|
+
# extend_hook :before_ready
|
223
|
+
#
|
224
|
+
# hook :before_ready do |resource|
|
225
|
+
# resource.orig_before_ready
|
226
|
+
#
|
227
|
+
# logger.info "Now I am really ready"
|
228
|
+
# end
|
229
|
+
#
|
230
|
+
# # if we simply want to overwrite the existing hook, just define the same hook without using extend_hook
|
231
|
+
#
|
232
|
+
# hook :before_ready do |resource|
|
233
|
+
# logger.info "Not sure if I am ready or not"
|
234
|
+
# end
|
235
|
+
#
|
236
|
+
def extend_hook(hook_name)
|
237
|
+
hook_name = hook_name.to_s
|
238
|
+
alias_method "orig_#{hook_name}", hook_name
|
239
|
+
end
|
240
|
+
|
241
|
+
# Extend existing work definition by alias existing method name as "orig_[method_name]"
|
242
|
+
#
|
243
|
+
# @see #extend_hook
|
244
|
+
#
|
245
|
+
def extend_work(work_name)
|
246
|
+
work_name = work_name.to_s
|
247
|
+
alias_method "orig_#{work_name}", work_name
|
248
|
+
end
|
249
|
+
|
250
|
+
# Extend existing configure definition
|
251
|
+
#
|
252
|
+
# @param [#to_s] configure_name name of existing configurable property
|
253
|
+
#
|
254
|
+
# Slightly different to extend_hook, the actual method_name defined by a configure property is "configure_[configurable_property_name]"
|
255
|
+
#
|
256
|
+
# @example to extend a configurable property
|
257
|
+
#
|
258
|
+
# configure :bob do |resource, value|
|
259
|
+
# resource.property.bob = value
|
260
|
+
# end
|
261
|
+
#
|
262
|
+
# # To extend this, simply do
|
263
|
+
#
|
264
|
+
# extend_configure :bob
|
265
|
+
#
|
266
|
+
# configure :bob do |resource, value|
|
267
|
+
# resource.orig_configure_bob(value)
|
268
|
+
# resource.property.bob = "New value: #{value}"
|
269
|
+
# end
|
270
|
+
#
|
271
|
+
# @see #extend_hook
|
272
|
+
#
|
273
|
+
def extend_configure(configure_name)
|
274
|
+
configure_name = configure_name.to_s
|
275
|
+
alias_method "orig_configure_#{configure_name}", "configure_#{configure_name}"
|
276
|
+
end
|
277
|
+
|
278
|
+
# Extend existing request definition
|
279
|
+
#
|
280
|
+
# @see #extend_hook
|
281
|
+
# @see #extend_configure
|
282
|
+
def extend_request(request_name)
|
283
|
+
request_name = request_name.to_s
|
284
|
+
alias_method "orig_request_#{request_name}", "request_#{request_name}"
|
285
|
+
end
|
286
|
+
|
153
287
|
end
|
154
288
|
end
|
@@ -0,0 +1,61 @@
|
|
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
|
+
#
|
24
|
+
# This module defines a Utility with some common work blocks that could be
|
25
|
+
# useful to any type of Resource Proxy (RP)
|
26
|
+
#
|
27
|
+
module OmfRc::Util::CommonTools
|
28
|
+
include OmfRc::ResourceProxyDSL
|
29
|
+
|
30
|
+
# This utility block logs an error/warn String S on the resource proxy side
|
31
|
+
# and publish an INFORM message on the resources pubsub topic. This INFORM
|
32
|
+
# message will have the type ERROR/WARN, and its 'reason' element set to the
|
33
|
+
# String S
|
34
|
+
#
|
35
|
+
# @yieldparam [String] msg the error or warning message
|
36
|
+
#
|
37
|
+
%w(error warn).each do |type|
|
38
|
+
work("log_inform_#{type}") do |res, msg|
|
39
|
+
logger.send(type, msg)
|
40
|
+
res.comm.publish(
|
41
|
+
res.uid,
|
42
|
+
OmfCommon::Message.inform(type.upcase) do |message|
|
43
|
+
message.element('reason' , msg)
|
44
|
+
end
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# This utility block returns true if its given value parameter is a Boolean,
|
50
|
+
# which in Ruby means that it is either of the class TrueClass or FalseClass
|
51
|
+
#
|
52
|
+
# @yieldparam [Object] obj the Object to test as Boolean
|
53
|
+
#
|
54
|
+
# [Boolean] true or fals
|
55
|
+
#
|
56
|
+
work('boolean?') do |res,obj|
|
57
|
+
result = false
|
58
|
+
result = true if obj.kind_of?(TrueClass) || obj.kind_of?(FalseClass)
|
59
|
+
result
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
require 'cocaine'
|
3
|
+
|
4
|
+
module OmfRc::Util::Hostapd
|
5
|
+
include OmfRc::ResourceProxyDSL
|
6
|
+
include Cocaine
|
7
|
+
|
8
|
+
# Initialise access point conf and pid location
|
9
|
+
#
|
10
|
+
work :init_ap_conf_pid do |device|
|
11
|
+
device.property.ap_conf = "/tmp/hostapd.#{device.hrn}.conf"
|
12
|
+
device.property.ap_pid = "/tmp/hostapd.#{device.hrn}.pid"
|
13
|
+
end
|
14
|
+
# Set up and run a hostapd instance
|
15
|
+
#
|
16
|
+
work :hostapd do |device|
|
17
|
+
device.init_ap_conf_pid
|
18
|
+
|
19
|
+
File.open(device.property.ap_conf, "w") do |f|
|
20
|
+
f << "driver=nl80211\ninterface=#{device.hrn}\nssid=#{device.property.essid}\nchannel=#{device.property.channel}\n"
|
21
|
+
f << "hw_mode=#{device.property.hw_mode}\n" if %w(a b g).include? device.property.hw_mode
|
22
|
+
if device.property.hw_mode == 'n'
|
23
|
+
if device.property.channel.to_i < 15
|
24
|
+
f << "hw_mode=g\n"
|
25
|
+
else device.property.channel.to_i > 15
|
26
|
+
f << "hw_mode=a\n"
|
27
|
+
end
|
28
|
+
f << "wmm_enabled=1\nieee80211n=1\nht_capab=[HT20-]\n"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
CommandLine.new("hostapd", "-B -P :ap_pid :ap_conf",
|
33
|
+
:ap_pid => device.property.ap_pid,
|
34
|
+
:ap_conf => device.property.ap_conf).run
|
35
|
+
end
|
36
|
+
|
37
|
+
work :stop_hostapd do |device|
|
38
|
+
begin
|
39
|
+
File.open(device.property.ap_pid,'r') do |f|
|
40
|
+
logger.debug "Stopping hostapd process at PID: #{device.property.ap_pid}"
|
41
|
+
CommandLine.new("kill", "-9 :pid", :pid => f.read.chomp).run
|
42
|
+
end
|
43
|
+
|
44
|
+
CommandLine.new("rm", "-f :ap_pid :ap_conf",
|
45
|
+
:ap_pid => device.property.ap_pid,
|
46
|
+
:ap_conf => device.property.ap_conf).run
|
47
|
+
rescue => e
|
48
|
+
logger.warn "Failed to clean hostapd and its related files '#{device.property.ap_pid}' and '#{device.property.ap_conf}'!"
|
49
|
+
logger.warn e.message
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'cocaine'
|
2
|
+
|
3
|
+
module OmfRc::Util::Ip
|
4
|
+
include OmfRc::ResourceProxyDSL
|
5
|
+
include Cocaine
|
6
|
+
|
7
|
+
request :ip_addr do |resource|
|
8
|
+
addr = CommandLine.new("ip", "addr show dev :device", :device => resource.hrn).run
|
9
|
+
addr && addr.chomp.match(/inet ([[0-9]\:\/\.]+)/) && $1
|
10
|
+
end
|
11
|
+
|
12
|
+
request :mac_addr do |resource|
|
13
|
+
addr = CommandLine.new("ip", "addr show dev :device", :device => resource.hrn).run
|
14
|
+
addr && addr.chomp.match(/link\/ether ([\d[a-f][A-F]\:]+)/) && $1
|
15
|
+
end
|
16
|
+
|
17
|
+
configure :ip_addr do |resource, value|
|
18
|
+
CommandLine.new("ip", "addr add :ip_address dev :device",
|
19
|
+
:ip_address => value,
|
20
|
+
:device => resource.hrn
|
21
|
+
).run
|
22
|
+
resource.request_ip_addr
|
23
|
+
end
|
24
|
+
|
25
|
+
work :interface_up do |resource|
|
26
|
+
CommandLine.new("ip", "link set :dev up", :dev => resource.hrn).run
|
27
|
+
end
|
28
|
+
end
|
data/lib/omf_rc/util/iw.rb
CHANGED
@@ -1,18 +1,34 @@
|
|
1
1
|
require 'hashie'
|
2
|
+
require 'cocaine'
|
2
3
|
|
3
4
|
module OmfRc::Util::Iw
|
4
5
|
include OmfRc::ResourceProxyDSL
|
6
|
+
include Cocaine
|
7
|
+
include Hashie
|
5
8
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
+
utility :ip
|
10
|
+
utility :wpa
|
11
|
+
utility :hostapd
|
12
|
+
|
13
|
+
# Parse iw help page and set up all configure methods available for iw command
|
14
|
+
#
|
15
|
+
CommandLine.new("iw", "help").run.chomp.gsub(/^\t/, '').split("\n").map {|v| v.match(/[phy|dev] <.+> set (\w+) .*/) && $1 }.compact.uniq.each do |p|
|
16
|
+
configure p do |device, value|
|
17
|
+
CommandLine.new("iw", "dev :dev set :property :value",
|
18
|
+
:dev => device.hrn,
|
19
|
+
:property => p,
|
20
|
+
:value => value).run
|
9
21
|
end
|
10
22
|
end
|
11
23
|
|
12
|
-
|
13
|
-
|
24
|
+
# Parse iw link command output and return as a mash
|
25
|
+
#
|
26
|
+
request :link do |device|
|
27
|
+
known_properties = Mash.new
|
28
|
+
|
29
|
+
command = CommandLine.new("iw", "dev :dev link", :dev => device.hrn)
|
14
30
|
|
15
|
-
|
31
|
+
command.run.chomp.gsub(/^\t/, '').split("\n").drop(1).each do |v|
|
16
32
|
v.match(/^(.+):\W*(.+)$/).tap do |m|
|
17
33
|
m && known_properties[m[1].downcase.gsub(/\W+/, '_')] = m[2].gsub(/^\W+/, '')
|
18
34
|
end
|
@@ -20,4 +36,101 @@ module OmfRc::Util::Iw
|
|
20
36
|
|
21
37
|
known_properties
|
22
38
|
end
|
39
|
+
|
40
|
+
# Parse iw info command output and return as a mash
|
41
|
+
#
|
42
|
+
request :info do |device|
|
43
|
+
known_properties = Mash.new
|
44
|
+
|
45
|
+
command = CommandLine.new("iw", "dev :dev info", :dev => device.hrn)
|
46
|
+
|
47
|
+
command.run.chomp.split("\n").drop(1).each do |v|
|
48
|
+
v.match(/^\W*(.+) (.+)$/).tap do |m|
|
49
|
+
m && known_properties[m[1].downcase.gsub(/\W+/, '_')] = m[2].gsub(/^\W+/, '')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
known_properties
|
54
|
+
end
|
55
|
+
|
56
|
+
# Delete current interface, clean up
|
57
|
+
#
|
58
|
+
work :delele_interface do |device|
|
59
|
+
CommandLine.new("iw", "dev :dev del", :dev => device.hrn).run
|
60
|
+
end
|
61
|
+
|
62
|
+
# Add interface to device
|
63
|
+
#
|
64
|
+
work :add_interface do |device, type|
|
65
|
+
CommandLine.new("iw", "phy :phy interface add :dev type :type",
|
66
|
+
:phy => device.property.phy,
|
67
|
+
:dev => device.hrn,
|
68
|
+
:type => type.to_s).run
|
69
|
+
end
|
70
|
+
|
71
|
+
# Set up or join a ibss network
|
72
|
+
#
|
73
|
+
work :join_ibss do |device|
|
74
|
+
CommandLine.new("iw", "dev :device ibss join :essid :frequency",
|
75
|
+
:device => device.hrn.to_s,
|
76
|
+
:essid => device.property.essid.to_s,
|
77
|
+
:frequency => device.property.frequency.to_s).run
|
78
|
+
end
|
79
|
+
|
80
|
+
# Validate internal properties based on interface mode
|
81
|
+
#
|
82
|
+
work :validate_iw_properties do |device|
|
83
|
+
raise ArgumentError, "Missing phyical device name" if device.property.phy.nil?
|
84
|
+
|
85
|
+
unless %w(master managed adhoc monitor).include? device.property.mode
|
86
|
+
raise ArgumentError, "Mode must be master, managed, adhoc, or monitor, got #{device.property.mode}"
|
87
|
+
end
|
88
|
+
|
89
|
+
case device.property.mode.to_sym
|
90
|
+
when :master
|
91
|
+
unless %w(a b g n).include? device.property.hw_mode
|
92
|
+
raise ArgumentError, "Hardware mode must be a, b, g, or n, got #{device.property.hw_mode}"
|
93
|
+
end
|
94
|
+
%w(channel essid).each do |p|
|
95
|
+
raise ArgumentError, "#{p} must not be nil" if device.property.send(p).nil?
|
96
|
+
end
|
97
|
+
when :managed
|
98
|
+
%w(essid).each do |p|
|
99
|
+
raise ArgumentError, "#{p} must not be nil" if device.property.send(p).nil?
|
100
|
+
end
|
101
|
+
when :adhoc
|
102
|
+
%w(essid frequency).each do |p|
|
103
|
+
raise ArgumentError, "#{p} must not be nil" if device.property.send(p).nil?
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Configure the interface with mode managed, master, adhoc or monitor
|
109
|
+
#
|
110
|
+
configure :mode do |device, value|
|
111
|
+
# capture value hash and store internally
|
112
|
+
device.property.update(value)
|
113
|
+
|
114
|
+
device.validate_iw_properties
|
115
|
+
|
116
|
+
device.delele_interface rescue logger.warn "Interface #{device.hrn} not found"
|
117
|
+
|
118
|
+
# TODO should just remove all interfaces from physical device, at least make it optional
|
119
|
+
|
120
|
+
case device.property.mode.to_sym
|
121
|
+
when :master
|
122
|
+
device.add_interface(:managed)
|
123
|
+
device.hostapd
|
124
|
+
when :managed
|
125
|
+
device.add_interface(:managed)
|
126
|
+
device.wpasup
|
127
|
+
when :adhoc
|
128
|
+
device.add_interface(:adhoc)
|
129
|
+
device.interface_up
|
130
|
+
device.join_ibss
|
131
|
+
when :monitor
|
132
|
+
device.add_interface(:monitor)
|
133
|
+
device.interface_up
|
134
|
+
end
|
135
|
+
end
|
23
136
|
end
|
data/lib/omf_rc/util/mock.rb
CHANGED
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'xmlrpc/client'
|
2
|
+
|
3
|
+
module OmfRc::Util::OpenflowTools
|
4
|
+
include OmfRc::ResourceProxyDSL
|
5
|
+
|
6
|
+
# The version of the flowvisor that this resource is able to control
|
7
|
+
FLOWVISOR_VERSION = "FV version=flowvisor-0.8.4"
|
8
|
+
|
9
|
+
# Parts of the regular expression that describes a flow entry for flowvisor
|
10
|
+
FLOWVISOR_FLOWENTRY_REGEXP_DEVIDED = [
|
11
|
+
/dpid=\[(?<device>.+)\]/,
|
12
|
+
/ruleMatch=\[OFMatch\[(?<match>.+)\]\]/,
|
13
|
+
/actionsList=\[Slice:(?<slice>.+)=(?<actions>.+)\]/,
|
14
|
+
/id=\[(?<id>.+)\]/,
|
15
|
+
/priority=\[(?<priority>.+)\]/
|
16
|
+
]
|
17
|
+
|
18
|
+
# The regular expression that describes a flow entry for flowvisor
|
19
|
+
FLOWVISOR_FLOWENTRY_REGEXP = /FlowEntry\[#{FLOWVISOR_FLOWENTRY_REGEXP_DEVIDED.join(',')},\]/
|
20
|
+
|
21
|
+
# The names of the flow (or flow entry) features
|
22
|
+
FLOW_FEATURES = %w{device match slice actions id priority}
|
23
|
+
|
24
|
+
# The names of the flow (or flow entry) features that are specified by the "match" feature
|
25
|
+
FLOW_MATCH_FEATURES = %w{in_port eth_src eth_dst ip_src ip_dst}
|
26
|
+
|
27
|
+
# The default features of a new flow (or flow entry)
|
28
|
+
FLOW_DEFAULTS = {
|
29
|
+
priority: "10",
|
30
|
+
actions: "4"
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
# Returns the flows (flow entries) that exist for this flowvisor
|
35
|
+
request :flows do |resource, filter = nil|
|
36
|
+
resource.flows(filter)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Internal function that creates a connection with a flowvisor instance and checks it
|
41
|
+
work :flowvisor_connection do |resource|
|
42
|
+
xmlrpc_client = XMLRPC::Client.new_from_hash(resource.property.flowvisor_connection_args)
|
43
|
+
xmlrpc_client.instance_variable_get("@http").verify_mode = OpenSSL::SSL::VERIFY_NONE
|
44
|
+
ping_msg = "test"
|
45
|
+
pong_msg = "PONG(#{resource.property.flowvisor_connection_args[:user]}): #{FLOWVISOR_VERSION}::#{ping_msg}"
|
46
|
+
raise "Connection with #{FLOWVISOR_VERSION} was not successful" if xmlrpc_client.call("api.ping", ping_msg) != pong_msg
|
47
|
+
xmlrpc_client
|
48
|
+
end
|
49
|
+
|
50
|
+
# Internal function that returns the flows (flow entries) that exist in the connected flowvisor instance
|
51
|
+
work :flows do |resource, filter = nil|
|
52
|
+
result = resource.flowvisor_connection.call("api.listFlowSpace")
|
53
|
+
result.map! do |line|
|
54
|
+
array_values = line.match(FLOWVISOR_FLOWENTRY_REGEXP)[1..-1]
|
55
|
+
# Example of above array's content: %w{00:00:...:01 in_port=1 test 4 30 10}
|
56
|
+
array_features_values_zipped = FLOW_FEATURES.zip(array_values)
|
57
|
+
# Example of above array's content: %w{device 00:00:...:01 match in_port=1 slice test actions 4 id 30 priority 10}
|
58
|
+
hash = Hashie::Mash.new(Hash[array_features_values_zipped])
|
59
|
+
# The following code adds extra features that are specified by the "match" feature
|
60
|
+
hash["match"].split(",").each do |couple|
|
61
|
+
array = couple.split("=")
|
62
|
+
hash[array[0]] = array[1]
|
63
|
+
end
|
64
|
+
hash
|
65
|
+
end
|
66
|
+
result.delete_if {|hash| hash["slice"] != resource.property.name} if resource.type.to_sym == :openflow_slice
|
67
|
+
FLOW_FEATURES.each do |feature|
|
68
|
+
result.delete_if {|hash| hash[feature] != filter[feature].to_s} if filter[feature]
|
69
|
+
end if filter
|
70
|
+
result
|
71
|
+
end
|
72
|
+
|
73
|
+
work :transformed_parameters do |resource, parameters|
|
74
|
+
|
75
|
+
match = []
|
76
|
+
FLOW_MATCH_FEATURES.each do |feature|
|
77
|
+
match << "#{feature}=#{parameters[feature]}" if parameters[feature]
|
78
|
+
end
|
79
|
+
match = match.join(",")
|
80
|
+
|
81
|
+
result = []
|
82
|
+
case parameters.operation
|
83
|
+
when "add"
|
84
|
+
h = Hashie::Mash.new
|
85
|
+
h.operation = parameters.operation.upcase
|
86
|
+
h.priority = parameters.priority ? parameters.priority.to_s : FLOW_DEFAULTS[:priority]
|
87
|
+
h.dpid = parameters.device.to_s
|
88
|
+
h.actions = "Slice:#{resource.property.name}=#{(parameters.actions ? parameters.actions : FLOW_DEFAULTS[:actions])}"
|
89
|
+
h.match = "OFMatch[#{match}]"
|
90
|
+
result << h
|
91
|
+
when "remove"
|
92
|
+
resource.flows(parameters).each do |f|
|
93
|
+
if f.match == match
|
94
|
+
h = Hashie::Mash.new
|
95
|
+
h.operation = parameters.operation.upcase
|
96
|
+
h.id = f.id
|
97
|
+
result << h
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
result
|
102
|
+
end
|
103
|
+
end
|