brocadesan 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/README +113 -0
  2. data/Rakefile +46 -0
  3. data/brocadesan.gemspec +14 -0
  4. data/lib/brocadesan.rb +8 -0
  5. data/lib/brocadesan/alias.rb +64 -0
  6. data/lib/brocadesan/config/brocade/san/switch_cmd_mapping.yml +116 -0
  7. data/lib/brocadesan/config/parser_mapping.yml +21 -0
  8. data/lib/brocadesan/device.rb +296 -0
  9. data/lib/brocadesan/monkey/string.rb +11 -0
  10. data/lib/brocadesan/provisioning.rb +894 -0
  11. data/lib/brocadesan/switch.rb +882 -0
  12. data/lib/brocadesan/wwn.rb +63 -0
  13. data/lib/brocadesan/zone.rb +60 -0
  14. data/lib/brocadesan/zone_configuration.rb +38 -0
  15. data/lib/meta_methods.rb +263 -0
  16. data/test/alias_test.rb +68 -0
  17. data/test/device_test.rb +203 -0
  18. data/test/output_helpers.rb +308 -0
  19. data/test/outputs/agshow_1.txt +7 -0
  20. data/test/outputs/agshow_1.yml +31 -0
  21. data/test/outputs/agshow_2.txt +4 -0
  22. data/test/outputs/agshow_2.yml +3 -0
  23. data/test/outputs/apt_policy_1.txt +6 -0
  24. data/test/outputs/apt_policy_1.yml +3 -0
  25. data/test/outputs/cfgshow_1.txt +5 -0
  26. data/test/outputs/cfgshow_1.yml +7 -0
  27. data/test/outputs/cfgshow_2.txt +31 -0
  28. data/test/outputs/cfgshow_2.yml +32 -0
  29. data/test/outputs/cfgshow_3.txt +9 -0
  30. data/test/outputs/cfgshow_3.yml +12 -0
  31. data/test/outputs/cfgtransshow_1.txt +2 -0
  32. data/test/outputs/cfgtransshow_1.yml +5 -0
  33. data/test/outputs/cfgtransshow_2.txt +3 -0
  34. data/test/outputs/cfgtransshow_2.yml +4 -0
  35. data/test/outputs/cfgtransshow_3.txt +3 -0
  36. data/test/outputs/cfgtransshow_3.yml +4 -0
  37. data/test/outputs/chassisname_1.txt +2 -0
  38. data/test/outputs/chassisname_1.yml +3 -0
  39. data/test/outputs/dlsshow_1.txt +4 -0
  40. data/test/outputs/dlsshow_1.yml +4 -0
  41. data/test/outputs/dlsshow_2.txt +4 -0
  42. data/test/outputs/dlsshow_2.yml +4 -0
  43. data/test/outputs/fabricshow_1.txt +10 -0
  44. data/test/outputs/fabricshow_1.yml +34 -0
  45. data/test/outputs/iodshow_1.txt +4 -0
  46. data/test/outputs/iodshow_1.yml +4 -0
  47. data/test/outputs/islshow_1.txt +6 -0
  48. data/test/outputs/islshow_1.yml +62 -0
  49. data/test/outputs/islshow_2.txt +2 -0
  50. data/test/outputs/islshow_2.yml +2 -0
  51. data/test/outputs/lscfg_show_1.txt +71 -0
  52. data/test/outputs/lscfg_show_1.yml +5 -0
  53. data/test/outputs/ns_1.txt +80 -0
  54. data/test/outputs/ns_1.yml +39 -0
  55. data/test/outputs/ns_2.txt +37 -0
  56. data/test/outputs/ns_2.yml +21 -0
  57. data/test/outputs/putty.log +1867 -0
  58. data/test/outputs/switch_1.txt +25 -0
  59. data/test/outputs/switch_1.yml +73 -0
  60. data/test/outputs/switch_2.txt +18 -0
  61. data/test/outputs/switch_2.yml +42 -0
  62. data/test/outputs/switch_3.txt +14 -0
  63. data/test/outputs/switch_3.yml +46 -0
  64. data/test/outputs/switchstatusshow_1.txt +21 -0
  65. data/test/outputs/switchstatusshow_1.yml +19 -0
  66. data/test/outputs/trunkshow_1.txt +8 -0
  67. data/test/outputs/trunkshow_1.yml +44 -0
  68. data/test/outputs/trunkshow_2.txt +2 -0
  69. data/test/outputs/trunkshow_2.yml +2 -0
  70. data/test/outputs/version_1.txt +6 -0
  71. data/test/outputs/version_1.yml +8 -0
  72. data/test/outputs/vf_switch_1.txt +25 -0
  73. data/test/outputs/vf_switch_1.yml +73 -0
  74. data/test/provisioning_test.rb +1043 -0
  75. data/test/switch_test.rb +476 -0
  76. data/test/wwn_test.rb +41 -0
  77. data/test/zone_configuration_test.rb +65 -0
  78. data/test/zone_test.rb +73 -0
  79. metadata +170 -0
@@ -0,0 +1,203 @@
1
+ require 'brocadesan'
2
+ require 'minitest/autorun'
3
+ require 'output_helpers'
4
+
5
+ class DeviceTest < MiniTest::Test
6
+ include SshStoryWriter
7
+ include Mock::Net::SSH
8
+ patch_revert
9
+
10
+ def setup
11
+ @device = TestDevice.new("test","test","test")
12
+ #Net::SSH::set_error ""
13
+ end
14
+
15
+ def test_device_setup
16
+ assert_instance_of TestDevice, @device
17
+ end
18
+
19
+ def test_prompt
20
+ assert_equal @device.prompt, TestDevice::DEFAULT_QUERY_PROMPT
21
+ @new_device = TestDevice.new("test","test","test",:prompt => "$ ")
22
+ assert_equal @new_device.prompt, "$ "
23
+ end
24
+
25
+ def test_get_mode
26
+ @device.instance_variable_set(:@opts,{:interactive=>true})
27
+ assert_equal "interactive", @device.get_mode
28
+
29
+ @device = TestDevice.new("test","test","test", :interactive=>true)
30
+ assert_equal "interactive", @device.get_mode
31
+
32
+ @device.set_mode("script")
33
+ assert_equal "script", @device.get_mode
34
+ end
35
+
36
+ def test_set_mode
37
+ assert_equal "interactive", @device.set_mode("interactive")
38
+
39
+ assert_equal "interactive", @device.set_mode(:interactive)
40
+
41
+ assert_equal "script", @device.set_mode("script")
42
+
43
+ assert_equal "script", @device.set_mode(:script)
44
+
45
+ assert_equal "script", @device.set_mode("blabla")
46
+ end
47
+
48
+ def test_session
49
+ #stub start with test connection coming from net/ssh/test
50
+ Net::SSH.stub :start, connection do
51
+ @device.session do
52
+ assert_instance_of Net::SSH::Connection::Session, @device.instance_variable_get(:@session)
53
+ assert_equal 1, @device.instance_variable_get(:@session_level)
54
+ @device.session do
55
+ assert_equal 2, @device.instance_variable_get(:@session_level)
56
+ end
57
+ refute @device.instance_variable_get(:@session).closed?
58
+ assert_equal 1, @device.instance_variable_get(:@session_level)
59
+ end
60
+ end
61
+ assert @device.instance_variable_get(:@session).closed?
62
+
63
+ # session can we called only with block, raises error otherwise
64
+ exp = assert_raises(TestDevice::Error) do
65
+ @device.session
66
+ end
67
+ end
68
+
69
+ def test_script_mode
70
+ #stub start with test connection coming from net/ssh/test
71
+ @device.set_mode :interactive
72
+ assert_equal "interactive", @device.get_mode
73
+ Net::SSH.stub :start, connection do
74
+ @device.script_mode do
75
+ assert_equal "script", @device.get_mode
76
+ end
77
+ end
78
+ assert_equal "interactive", @device.get_mode
79
+
80
+ # this can we called only with block, raises error otherwise
81
+ exp = assert_raises(LocalJumpError) do
82
+ @device.script_mode
83
+ end
84
+ end
85
+
86
+ def test_interactive_mode
87
+ #stub start with test connection coming from net/ssh/test
88
+ @device.set_mode :script
89
+ assert_equal "script", @device.get_mode
90
+ Net::SSH.stub :start, connection do
91
+ @device.interactive_mode do
92
+ assert_equal "interactive", @device.get_mode
93
+ end
94
+ end
95
+ assert_equal "script", @device.get_mode
96
+
97
+ # this can we called only with block, raises error otherwise
98
+ exp = assert_raises(LocalJumpError) do
99
+ @device.interactive_mode
100
+ end
101
+ end
102
+
103
+ def test_query_in_session
104
+ cmds = ["test"]
105
+ exp_response = write_non_interactive_story(cmds,["test_ok"],TestDevice::DEFAULT_QUERY_PROMPT)
106
+ Net::SSH.stub :start, connection do
107
+ @device.session do
108
+ response=@device.query(cmds[0])
109
+ assert_instance_of TestDevice::Response, response
110
+ assert_equal exp_response, response.data
111
+ end
112
+ end
113
+ end
114
+
115
+ def test_interactive_query
116
+ cmds = ["cfgsave","y"]
117
+ replies = ["confirm? [y,n]"]
118
+ exp_response = write_interactive_story(cmds,replies,TestDevice::DEFAULT_QUERY_PROMPT)
119
+
120
+ @device.set_mode("interactive")
121
+ # connection is net/ssh/test method
122
+ @device.instance_variable_set(:@session,connection)
123
+
124
+ response=nil
125
+ assert_scripted do
126
+
127
+ response=@device.query("cfgsave","y")
128
+
129
+ assert_equal exp_response, response.data
130
+ end
131
+ assert_instance_of TestDevice::Response, response
132
+
133
+ # response safety net test for infinite newline response
134
+ # create story with 150 newline commands
135
+ cmds = Array.new(150, "")
136
+ replies = Array.new(150,"confirm? [y,n]")
137
+ exp_response = write_interactive_story(cmds,replies,TestDevice::DEFAULT_QUERY_PROMPT)
138
+
139
+
140
+ # this is pure hack, this raises RuntimeError as the connection script is expecting 150 responses
141
+ # but there are only 100 if them as expected
142
+ # since the script did not match reality we had to assume this worked
143
+ # we do not get any response so we cannot check it precisly
144
+ # but we at least check the internal retries value
145
+ # not the best test but so far the best I came up with
146
+
147
+ assert_raises RuntimeError do
148
+ # story contains 150 new line responses
149
+ # this closses the channel after 100
150
+ @device.query("")
151
+ end
152
+
153
+ assert_equal 100, @device.instance_variable_get(:@retries)
154
+ end
155
+
156
+ def test_non_interactive_query
157
+ cmds = ["cfgshow","switchshow"]
158
+ replies = ["not_available","is_available"]
159
+ error = "cannot execute this"
160
+ # write non itneractive ssh story that should play out when running the query
161
+ exp_response = write_non_interactive_story(cmds,replies,TestDevice::DEFAULT_QUERY_PROMPT)
162
+
163
+ # connection is net/ssh/test method
164
+ @device.instance_variable_set(:@session,connection)
165
+ response=nil
166
+ assert_scripted do
167
+
168
+ response=@device.query(*cmds)
169
+
170
+ assert_equal exp_response, response.data
171
+ end
172
+ assert_instance_of TestDevice::Response, response
173
+
174
+ #errors
175
+ # write story endig with error
176
+ exp_response = write_failed_simple_story(cmds[0],error,TestDevice::DEFAULT_QUERY_PROMPT)
177
+ exp = assert_raises TestDevice::Error do
178
+ @device.query(cmds[0])
179
+ end
180
+ assert_equal "#{error}\n", exp.message
181
+ end
182
+ end
183
+
184
+ class ResponseTest < MiniTest::Test
185
+ def setup
186
+ @response = TestDevice::Response.new("> ")
187
+ end
188
+
189
+ def test_parse
190
+ #parse should end with end
191
+ @response.parsed="test"
192
+ @response.parse
193
+ assert_equal a={:parsing_position=>"end"}, @response.parsed
194
+ end
195
+
196
+ def test_prompt
197
+ assert_equal @response.instance_variable_get(:@prompt), "> "
198
+ end
199
+ end
200
+
201
+ class TestDevice
202
+ include SshDevice
203
+ end
@@ -0,0 +1,308 @@
1
+ require 'yaml'
2
+ require 'net/ssh/test'
3
+
4
+ module OutputReader
5
+
6
+ attr_accessor :output_dir
7
+
8
+ def read_all_starting_with(regexp,&block)
9
+ @output_dir=Dir.pwd if @output_dir.nil?
10
+ files=Dir.glob(File.join(@output_dir,"#{regexp}*.txt"))
11
+ files.each do |f|
12
+ contents = File.read(f)
13
+ yield f, contents
14
+ end
15
+ end
16
+
17
+ def read_yaml_for(file)
18
+ parts=file.split(".")
19
+ file_name=parts[0..-2].join(".")
20
+ YAML.load(File.read("#{file_name}.yml"))
21
+ end
22
+
23
+ def new_mock_response
24
+ Brocade::SAN::Switch::Response.new("> ")
25
+ end
26
+ end
27
+
28
+ # this is used to check the _exec methods in device
29
+ # for the remaining test see the below monkeypath mock
30
+ module SshStoryWriter
31
+ include Net::SSH::Test
32
+
33
+ # creates a interactive ssh story for testing and returns expeced response for that story
34
+ def write_interactive_story(cmds,partial_replies,prompt="")
35
+ cmd=cmds.shift
36
+ response = "#{prompt}"
37
+ story do |session|
38
+ channel = session.opens_channel
39
+ channel.sends_request_pty
40
+ channel.sends_exec cmd
41
+ response +="#{cmd}\n"
42
+ partial_replies.each_with_index do |pr,i|
43
+ channel.gets_data pr
44
+ channel.sends_data "#{cmds[i]}\n"
45
+
46
+ response +="#{pr}"
47
+ response +="#{cmds[i]}\n"
48
+ end
49
+ channel.gets_close
50
+ channel.sends_close
51
+ end
52
+
53
+ return response
54
+ end
55
+
56
+ # creates non interactive ssh story for testing and returns expeced response for that story
57
+ def write_non_interactive_story(cmds,replies,prompt="")
58
+ response = ""
59
+ story do |session|
60
+ replies.each_with_index do |reply,i|
61
+ channel = session.opens_channel
62
+ channel.sends_exec cmds[i]
63
+ channel.gets_data reply
64
+ channel.gets_close
65
+ channel.sends_close
66
+ response +="#{prompt}#{cmds[i]}\n"
67
+ response +="#{reply}\n"
68
+ end
69
+
70
+ end
71
+
72
+ return response
73
+ end
74
+
75
+ def write_failed_simple_story(cmd,error,prompt="")
76
+ response = ""
77
+ story do |session|
78
+ channel = session.opens_channel
79
+ channel.sends_exec cmd
80
+ channel.gets_extended_data error
81
+ #session.gets_channel_extended_data(channel, error)
82
+ channel.gets_close
83
+ channel.sends_close
84
+ response +="#{prompt}#{cmd}\n"
85
+ #response +="#{reply}\n"
86
+
87
+ end
88
+
89
+ return response
90
+ end
91
+ end
92
+
93
+ # patch for request_pry based on https://github.com/test-kitchen/test-kitchen/blob/master/spec/kitchen/ssh_spec.rb#L86-L113
94
+ module Net
95
+
96
+ module SSH
97
+
98
+ module Test
99
+
100
+ class Channel
101
+
102
+ def sends_request_pty
103
+ pty_data = ["xterm", 80, 24, 640, 480, "\0"]
104
+
105
+ script.events << Class.new(Net::SSH::Test::LocalPacket) do
106
+ def types
107
+ if @type == 98 && @data[1] == "pty-req"
108
+ @types ||= [
109
+ :long, :string, :bool, :string,
110
+ :long, :long, :long, :long, :string
111
+ ]
112
+ else
113
+ super
114
+ end
115
+ end
116
+ end.new(:channel_request, remote_id, "pty-req", false, *pty_data)
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ # simplified mock module that is used to monkey patch/stub Net::SSH.start
124
+ # the stubed method resturns mocked Session
125
+ # the session for now response to exec!, closed? and close
126
+ # which is sufficient for my testing
127
+ # Usage:
128
+ # put following into subclasees MiniTest::Test that should use this mock
129
+ # include Mock::Net::SSH
130
+ # patch_set
131
+ #
132
+ # or
133
+ #
134
+ # put following into subclasees MiniTest::Test that should not use this mock
135
+ # mention this explicitely as some other test might have set it
136
+ # include Mock::Net::SSH
137
+ # patch_revert
138
+ #
139
+ module Mock
140
+ module Net
141
+ module SSH
142
+
143
+ def self.included(base)
144
+ base.extend(ClassMethods)
145
+ end
146
+
147
+ def initialize(*args)
148
+ patch_configure
149
+ super(*args)
150
+ end
151
+
152
+ def patch_configure; end
153
+
154
+ module ClassMethods
155
+ def patch_set
156
+ alias_method :patch_configure, :monkey_patch
157
+ end
158
+
159
+ def patch_revert
160
+ alias_method :patch_configure, :monkey_patch_revert
161
+ end
162
+ end
163
+
164
+ @@data="Response"
165
+ @@error=""
166
+ @@channel="channel"
167
+
168
+ def self.get_data
169
+ @@data
170
+ end
171
+
172
+ def self.get_error
173
+ @@error
174
+ end
175
+
176
+ def self.get_channel
177
+ @@channel
178
+ end
179
+
180
+ def self.set_data(x)
181
+ @@data=x
182
+ end
183
+
184
+ def self.set_error(x)
185
+ @@error=x
186
+ end
187
+
188
+ def self.set_channel(x)
189
+ @@channel=x
190
+ end
191
+
192
+ class Session
193
+ def exec!(command, &block)
194
+ @data=Mock::Net::SSH::get_data.dup
195
+ @error=Mock::Net::SSH::get_error.dup
196
+ @ch=Mock::Net::SSH::get_channel.dup
197
+
198
+ if block
199
+ block.call(@ch, :stdout, @data)
200
+ block.call(@ch, :stderr, @error)
201
+ else
202
+ $stdout.print(data)
203
+ end
204
+ end
205
+
206
+ def close
207
+ @closed=true
208
+ end
209
+
210
+ def closed?
211
+ @closed.nil? ? false : @closed
212
+ end
213
+ end
214
+
215
+ private
216
+ def monkey_patch
217
+ ::Net::SSH.instance_eval do
218
+ singleton = self.singleton_class
219
+ if !singleton.respond_to? :old_start
220
+ singleton.send(:alias_method, :old_start, :start)
221
+
222
+ def self.start(host, user, options={}, &block)
223
+ if block
224
+ yield Mock::Net::SSH::Session.new
225
+ else
226
+ return Mock::Net::SSH::Session.new
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ def monkey_patch_revert
234
+ ::Net::SSH.instance_eval do
235
+ if self.singleton_class.respond_to? :old_start
236
+ self.singleton_class.send(:alias_method, :start, :old_start)
237
+ self.singleton_class.send(:undef_method, :old_start)
238
+ end
239
+ end
240
+ end
241
+ end
242
+ end
243
+ end
244
+
245
+ module Kernel
246
+ # stubs query method by another method that assiges the parameters to @test_string and runing original query
247
+ def query_stub(&block)
248
+ self.instance_eval do
249
+ self.singleton_class.send(:alias_method, :old_query, :query)
250
+ @query_string=""
251
+ def query(*cmds)
252
+ @query_string||=""
253
+ @query_string<<cmds.join(",")
254
+ old_query(*cmds)
255
+ end
256
+ end
257
+ yield
258
+ self.instance_eval do
259
+ self.singleton_class.send(:alias_method, :query, :old_query)
260
+ self.singleton_class.send(:undef_method, :old_query)
261
+ end
262
+ end
263
+
264
+ # stubs query method by another method that assiges the parameters to @test_string and runing original query
265
+ def abort_transaction_stub(&block)
266
+ self.instance_eval do
267
+ self.singleton_class.send(:alias_method, :old_abort_transaction, :abort_transaction)
268
+ def abort_transaction
269
+ @trans_aborted=true
270
+ old_abort_transaction
271
+ end
272
+ end
273
+ yield
274
+ self.instance_eval do
275
+ self.singleton_class.send(:alias_method, :abort_transaction, :old_abort_transaction)
276
+ self.singleton_class.send(:undef_method, :old_abort_transaction)
277
+ end
278
+ end
279
+
280
+ # stubs query method by another method that assiges the parameters to @test_string and runing original query
281
+ def raise_if_obj_do_not_exist_stub(&block)
282
+ self.instance_eval do
283
+ self.singleton_class.send(:alias_method, :old_raise_if_obj_do_not_exist, :raise_if_obj_do_not_exist)
284
+ def raise_if_obj_do_not_exist(obj)
285
+ if !@run.nil?
286
+ old_raise_if_obj_do_not_exist(obj)
287
+ end
288
+ @run=true
289
+ end
290
+ end
291
+ yield
292
+ self.instance_eval do
293
+ self.singleton_class.send(:alias_method, :raise_if_obj_do_not_exist, :old_raise_if_obj_do_not_exist)
294
+ self.singleton_class.send(:undef_method, :old_raise_if_obj_do_not_exist)
295
+ end
296
+ end
297
+
298
+ def multistub(cmds,&block)
299
+ if !cmds.empty?
300
+ cmd = cmds.shift
301
+ stub cmd[0], cmd[1] do
302
+ multistub cmds, &block
303
+ end
304
+ else
305
+ yield
306
+ end
307
+ end
308
+ end