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,164 @@
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 handle the
25
+ # installation of software on a given OS platform
26
+ #
27
+ module OmfRc::Util::PlatformTools
28
+ include OmfRc::ResourceProxyDSL
29
+
30
+ utility :common_tools
31
+
32
+ # This utility block logs attempts to detect the OS platform on which it is
33
+ # currently running. Right now it can recognise the following platform:
34
+ # - Ubuntu (by looking for an Ubuntu string in /etc/*release files)
35
+ # - Fedora (by looking for a Fedora string in /etc/*release files)
36
+ #
37
+ # Further methods and OS platform may be supported later
38
+ #
39
+ # [Symbol] either :unknown | :ubuntu | :fedora
40
+ #
41
+ work('detect_platform') do
42
+ r = `cat /etc/*release`.upcase
43
+ platform = :unknown
44
+ platform = :ubuntu if r.include?('UBUNTU')
45
+ platform = :fedora if r.include?('FEDORA')
46
+ platform
47
+ end
48
+
49
+ # This utility block logs attempts to validate if a given package name is
50
+ # a valid one or not. Right now it checks the following:
51
+ # - if the given pkg name is not nil
52
+ # - if the given pkg name has a size > 0
53
+ #
54
+ # Further checks may be implemented later
55
+ # (e.g. is the pkg provided by any known repository, etc...)
56
+ #
57
+ # @yieldparam [String] pkg_name the package name to check
58
+ #
59
+ # [Boolean] true or fals
60
+ #
61
+ work('valid_pkg_name') do |res, pkg_name|
62
+ valid_name = false
63
+ plat = res.detect_platform
64
+ logger.debug "Platform: '#{plat}' - Installing: '#{pkg_name}'"
65
+ valid_name = true unless pkg_name.nil? || (pkg_name.to_s.size == 0)
66
+ res.log_inform_error "Package name is not defined for "+
67
+ "platform: '#{plat}'. Abort install!" unless valid_name
68
+ valid_name
69
+ end
70
+
71
+ # This utility block install a package on an Ubuntu platform using
72
+ # the underlying apt-get tool
73
+ #
74
+ # @yieldparam [String] pkg_name the package name to install
75
+ #
76
+ work('install_ubuntu') do |res, pkg_name|
77
+ next false unless res.valid_pkg_name(pkg_name)
78
+ ExecApp.new("#{res.hrn.nil? ? res.uid : res.hrn}_INSTALL",
79
+ res,
80
+ "LANGUAGE='C' LANG='C' "+
81
+ "LC_ALL='C' DEBIAN_FRONTEND='noninteractive' "+
82
+ "apt-get install --reinstall --allow-unauthenticated -qq "+
83
+ "#{pkg_name}")
84
+ end
85
+
86
+ # This utility block install a package on an Fedora platform using
87
+ # the underlying yum tool
88
+ #
89
+ # @yieldparam [String] pkg_name the package name to install
90
+ #
91
+ work('install_fedora') do |res, pkg_name|
92
+ next false unless res.valid_pkg_name(pkg_name)
93
+ ExecApp.new("#{res.hrn.nil? ? res.uid : res.hrn}_INSTALL",
94
+ res,
95
+ "/usr/bin/yum -y install #{pkg_name}")
96
+ end
97
+
98
+ # This utility block install a software from a tarball archive. It first
99
+ # tries to download the tarball at a given URI (if it has not been
100
+ # downloaded earlier), then it unarchives it at the given install_path
101
+ #
102
+ # @yieldparam [String] pkg_name the package name to install
103
+ # @yieldparam [String] install_path the path where to install this package
104
+ #
105
+ work('install_tarball') do |res, pkg_name, install_path|
106
+ next false unless res.valid_pkg_name(pkg_name)
107
+ require 'net/http'
108
+ require 'uri'
109
+ require 'digest/md5'
110
+
111
+ file = "/tmp/#{File.basename(pkg_name)}"
112
+ if file.empty?
113
+ res.log_inform_error "Failed to parse URI '#{pkg_name}'. Abort install!"
114
+ next false
115
+ end
116
+
117
+ eTagFile = "#{file}.etag"
118
+ download = true
119
+ cmd = ""
120
+ remoteETag = nil
121
+
122
+ # get the ETag from the HTTP header
123
+ begin
124
+ uri = URI.parse(pkg_name)
125
+ result = Net::HTTP.start(uri.host, uri.port) do |http|
126
+ header = http.request_head(pkg_name)
127
+ remoteETag = header['etag']
128
+ end
129
+ rescue => err
130
+ res.log_inform_error "Failed to access URL '#{pkg_name}'"+
131
+ " (error: #{err}). Abort install!"
132
+ next false
133
+ end
134
+
135
+ # if we have the file and its ETag locally,
136
+ # compare it to the ETag of the remote file
137
+ if File.exists?(file) && File.exists?(eTagFile)
138
+ f=File.open(eTagFile,'r')
139
+ localETag=f.gets
140
+ f.close
141
+ download = false if remoteETag == localETag
142
+ end
143
+
144
+ # download the file & store the ETag if necessary
145
+ if download
146
+ logger.debug "Downloading '#{pkg_name}'"
147
+ # -m -nd overwrites existing files
148
+ cmd="wget -P /tmp -m -nd -q #{pkg_name};"
149
+ unless remoteETag.empty?
150
+ f=File.open(eTagFile,'w')
151
+ f.write remoteETag
152
+ f.close
153
+ end
154
+ else
155
+ logger.debug "Local file '#{file}' already exists and is "+
156
+ "identical to '#{pkg_name}'"
157
+ end
158
+ # Finally unarchive the file at the requested install path
159
+ cmd += "tar -C #{install_path} -xf #{file}"
160
+ id = "#{res.hrn.nil? ? res.uid : res.hrn}_INSTALL"
161
+ ExecApp.new(id, res, cmd, false)
162
+ end
163
+
164
+ end
@@ -0,0 +1,42 @@
1
+ require 'hashie'
2
+ require 'cocaine'
3
+
4
+ module OmfRc::Util::Wpa
5
+ include OmfRc::ResourceProxyDSL
6
+ include Cocaine
7
+
8
+ # Initialise wpa related conf and pid location
9
+ #
10
+ work :init_wpa_conf_pid do |device|
11
+ device.property.wpa_conf = "/tmp/wpa.#{device.hrn}.conf"
12
+ device.property.wpa_pid = "/tmp/wpa.#{device.hrn}.pid"
13
+ end
14
+
15
+ work :wpasup do |device|
16
+ device.init_wpa_conf_pid
17
+
18
+ File.open(device.property.wpa_conf, "w") do |f|
19
+ f << "network={\n ssid=\"#{device.property.essid}\"\n scan_ssid=1\n key_mgmt=NONE\n}"
20
+ end
21
+ CommandLine.new("wpa_supplicant", "-B -P :wpa_pid -i:dev -c:wpa_conf",
22
+ :dev => device.hrn,
23
+ :wpa_conf => device.property.wpa_conf,
24
+ :wpa_pid => device.property.wpa_pid).run
25
+ end
26
+
27
+ work :stop_wpa do |device|
28
+ begin
29
+ File.open(device.property.wpa_pid,'r') do |f|
30
+ logger.debug "Stopping wpa supplicant at PID: #{device.property.wpa_pid}"
31
+ CommandLine.new("kill", "-9 :pid", :pid => f.read.chomp).run
32
+ end
33
+
34
+ CommandLine.new("rm", "-f :wpa_pid :wpa_conf",
35
+ :wpa_pid => device.property.wpa_pid,
36
+ :wpa_conf => device.property.wpa_conf).run
37
+ rescue => e
38
+ logger.warn "Failed to clean wpa supplicant and its related files '#{device.property.wpa_pid}' and '#{device.property.wpa_conf}'!"
39
+ logger.warn e.message
40
+ end
41
+ end
42
+ end
@@ -1,3 +1,3 @@
1
1
  module OmfRc
2
- VERSION = "6.0.0.pre.5"
2
+ VERSION = "6.0.0.pre.6"
3
3
  end
data/omf_rc.gemspec CHANGED
@@ -19,7 +19,9 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  # specify any dependencies here; for example:
22
- s.add_development_dependency "minitest", "~> 2.11.3"
22
+ s.add_development_dependency "minitest", "~> 3.2"
23
23
  s.add_development_dependency "em-minitest-spec", "~> 1.1.1"
24
+ s.add_development_dependency "simplecov"
24
25
  s.add_runtime_dependency "omf_common", "~> 6.0.0.pre"
26
+ s.add_runtime_dependency "cocaine", "~> 0.3.0"
25
27
  end
@@ -0,0 +1,5 @@
1
+ 3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
2
+ link/ether 00:00:00:29:00:00 brd ff:ff:ff:ff:ff:ff
3
+ inet 192.168.1.124/24 brd 192.168.1.255 scope global wlan0
4
+ inet6 fe80::2677:3ff:fe29:4d5c/64 scope link
5
+ valid_lft forever preferred_lft forever
@@ -0,0 +1,4 @@
1
+ Interface wlan0
2
+ ifindex 3
3
+ type managed
4
+ wiphy 0
@@ -0,0 +1,6 @@
1
+ DRIVER=iwlwifi
2
+ PCI_CLASS=28000
3
+ PCI_ID=8086:4238
4
+ PCI_SUBSYS_ID=8086:1111
5
+ PCI_SLOT_NAME=0000:03:00.0
6
+ MODALIAS=pci:v00008086d00004238sv00008086sd00001111bc02sc80i00
File without changes
@@ -0,0 +1,6 @@
1
+ DRIVER=e1000e
2
+ PCI_CLASS=20000
3
+ PCI_ID=8086:1502
4
+ PCI_SUBSYS_ID=17AA:21CE
5
+ PCI_SLOT_NAME=0000:00:19.0
6
+ MODALIAS=pci:v00008086d00001502sv000017AAsd000021CEbc02sc00i00
@@ -0,0 +1,2 @@
1
+ INTERFACE=eth0
2
+ IFINDEX=2
@@ -0,0 +1,6 @@
1
+ DRIVER=iwlwifi
2
+ PCI_CLASS=28000
3
+ PCI_ID=8086:4238
4
+ PCI_SUBSYS_ID=8086:1111
5
+ PCI_SLOT_NAME=0000:03:00.0
6
+ MODALIAS=pci:v00008086d00004238sv00008086sd00001111bc02sc80i00
@@ -0,0 +1,3 @@
1
+ DEVTYPE=wlan
2
+ INTERFACE=wlan0
3
+ IFINDEX=3
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ describe OmfRc::MessageProcessError do
4
+ it "must be able to initialised" do
5
+ mpe = OmfRc::MessageProcessError.new('test_context_id', 'inform_to_address', 'error_messsage')
6
+ mpe.context_id.must_equal 'test_context_id'
7
+ mpe.inform_to.must_equal 'inform_to_address'
8
+ mpe.message.must_equal 'error_messsage'
9
+ mpe.must_be_kind_of StandardError
10
+ end
11
+ end
@@ -1,5 +1,4 @@
1
1
  require 'test_helper'
2
- require 'mock_helper'
3
2
  require 'omf_rc/resource_factory'
4
3
 
5
4
  describe OmfRc::ResourceFactory do
@@ -17,5 +16,13 @@ describe OmfRc::ResourceFactory do
17
16
  mock.request_nothing.must_equal mock.uid
18
17
  mock.must_respond_to :configure_nothing
19
18
  end
19
+
20
+ it "must be able to load addtional proxies from local folder" do
21
+ Dir.stub :[], ["non_exist_folder/test.rb"] do
22
+ proc do
23
+ OmfRc::ResourceFactory.load_addtional_resource_proxies("non_exist_folder")
24
+ end.must_raise LoadError
25
+ end
26
+ end
20
27
  end
21
28
  end
@@ -1,4 +1,5 @@
1
1
  require 'test_helper'
2
+ require 'em/minitest/spec'
2
3
  require 'omf_rc/resource_factory'
3
4
 
4
5
  include OmfRc::ResourceProxy
@@ -63,7 +64,9 @@ describe AbstractResource do
63
64
 
64
65
  describe "when destroyed" do
65
66
  it "must destroy itself together with any resources created by it" do
66
- @node.release
67
+ child = @node.create(:wifi, { hrn: 'default_wifi' })
68
+ @node.children.wont_be_empty
69
+ @node.release(child.uid)
67
70
  @node.children.must_be_empty
68
71
  end
69
72
  end
@@ -81,4 +84,57 @@ describe AbstractResource do
81
84
  @node.request_hrn.must_equal 'bob'
82
85
  end
83
86
  end
87
+
88
+ describe "when interacted with communication layer" do
89
+ include EM::MiniTest::Spec
90
+
91
+ before do
92
+ @client = Blather::Client.new
93
+ @stream = MiniTest::Mock.new
94
+ @stream.expect(:send, true, [Blather::Stanza])
95
+ @client.post_init @stream, Blather::JID.new('n@d/r')
96
+ @xmpp = Class.new { include OmfCommon::DSL::Xmpp }.new
97
+ end
98
+
99
+ it "must be able to send inform message" do
100
+ @node.comm.stub :publish, proc { |inform_to, message| message.valid?.must_equal true} do
101
+ @node.inform(:created, resource_id: 'bob', context_id: 'id', inform_to: 'topic')
102
+ @node.inform(:released, resource_id: 'bob', context_id: 'id', inform_to: 'topic')
103
+ @node.inform(:status, status: { key: 'value' }, context_id: 'id', inform_to: 'topic')
104
+ @node.inform(:created, resource_id: 'bob', context_id: 'id', inform_to: 'topic')
105
+ @node.inform(:warn, 'going to fail')
106
+ @node.inform(:error, 'failed')
107
+ @node.inform(:warn, Exception.new('going to fail'))
108
+ @node.inform(:error, Exception.new('failed'))
109
+ @node.inform(:failed, Exception.new('failed'))
110
+ end
111
+
112
+ lambda { @node.inform(:failed, 'bob') }.must_raise ArgumentError
113
+ lambda { @node.inform(:created, 'topic') }.must_raise ArgumentError
114
+ lambda { @node.inform(:status, 'topic') }.must_raise ArgumentError
115
+ end
116
+
117
+ it "must be able to connect & disconnect" do
118
+ Blather::Client.stub :new, @client do
119
+ Blather::Stream::Client.stub(:start, @client) do
120
+ @node = OmfRc::ResourceFactory.new(:node, { hrn: 'default_node', user: 'bob', password: 'pw', server: 'example.com'}, @xmpp)
121
+ @client.stub(:connected?, true) do
122
+ @node.connect
123
+ @node.comm.jid.inspect.must_equal "bob@example.com"
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ describe "when request/configure property not pre-defined in proxy" do
131
+ it "must try property hash" do
132
+ @node.property[:bob] = "bob"
133
+ @node.request_bob.must_equal "bob"
134
+ @node.configure_bob("not_bob")
135
+ @node.request_bob.must_equal "not_bob"
136
+ proc { @node.request_bobs_cousin }.must_raise NoMethodError
137
+ proc { @node.bobs_cousin }.must_raise NoMethodError
138
+ end
139
+ end
84
140
  end