trema 0.5.1 → 0.6.0

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/Rakefile +2 -0
  4. data/bin/trema +17 -2
  5. data/cucumber.yml +7 -0
  6. data/features/.nav +47 -0
  7. data/features/{logging.feature → api/logging.feature} +1 -7
  8. data/features/{send_flow_mod_add.feature → api/send_flow_mod_add.feature} +2 -7
  9. data/features/handlers/barrier_reply.feature +30 -0
  10. data/features/{echo_reply_handler.feature → handlers/echo_reply.feature} +14 -13
  11. data/features/handlers/hello_failed.feature +56 -0
  12. data/features/handlers/packet_in.feature +32 -0
  13. data/features/handlers/start.feature +31 -0
  14. data/features/handlers/switch_disconnected.feature +34 -0
  15. data/features/handlers/switch_ready.feature +26 -0
  16. data/features/logger/debug.feature +41 -0
  17. data/features/logger/error.feature +41 -0
  18. data/features/logger/fatal.feature +41 -0
  19. data/features/logger/info.feature +41 -0
  20. data/features/logger/warn.feature +41 -0
  21. data/features/step_definitions/README.txt +2 -0
  22. data/features/step_definitions/dump_flows_steps.rb +13 -0
  23. data/features/step_definitions/rest_api_steps.rb +40 -0
  24. data/features/step_definitions/show_stats_steps.rb +31 -4
  25. data/features/step_definitions/trema_steps.rb +72 -0
  26. data/features/support/hooks.rb +4 -1
  27. data/features/trema_delete_link/README.md +5 -0
  28. data/features/{trema_delete_link.feature → trema_delete_link/delete_link.feature} +9 -13
  29. data/features/trema_delete_link/socket_dir_option.feature +12 -0
  30. data/features/trema_killall/README.md +5 -0
  31. data/features/trema_killall/all_option.feature +20 -0
  32. data/features/{trema_killall.feature → trema_killall/killall.feature} +10 -28
  33. data/features/trema_killall/socket_dir_option.feature +38 -0
  34. data/features/trema_run/README.md +5 -0
  35. data/features/trema_run/conf_option.feature +66 -0
  36. data/features/trema_run/daemonize_option.feature +19 -0
  37. data/features/trema_run/log_dir_option.feature +32 -0
  38. data/features/trema_run/logging_level_option.feature +30 -0
  39. data/features/trema_run/openflow13_option.feature +39 -0
  40. data/features/trema_run/pid_dir_option.feature +32 -0
  41. data/features/trema_run/port_option.feature +32 -0
  42. data/features/trema_run/run.feature +83 -0
  43. data/features/trema_run/socket_dir_option.feature +34 -0
  44. data/features/trema_start/README.md +5 -0
  45. data/features/trema_start/socket_dir_option.feature +9 -0
  46. data/features/{trema_start.feature → trema_start/start.feature} +23 -24
  47. data/features/trema_stop/README.md +5 -0
  48. data/features/trema_stop/socket_dir_option.feature +9 -0
  49. data/features/{trema_stop.feature → trema_stop/stop.feature} +7 -12
  50. data/lib/trema/command.rb +15 -2
  51. data/lib/trema/controller.rb +16 -2
  52. data/lib/trema/switch.rb +25 -26
  53. data/lib/trema/version.rb +1 -1
  54. data/trema.gemspec +8 -7
  55. metadata +73 -26
  56. data/features/cleanup_on_failure.feature +0 -118
  57. data/features/step_definitions/README.md +0 -7
  58. data/features/trema_run.feature +0 -72
@@ -0,0 +1,83 @@
1
+ Feature: run
2
+ @sudo
3
+ Scenario: run controller_file
4
+ Given a file named "hello.rb" with:
5
+ """ruby
6
+ class Hello < Trema::Controller
7
+ def start(_args)
8
+ logger.info 'Hello'
9
+ end
10
+ end
11
+ """
12
+ When I run `trema run hello.rb` interactively
13
+ Then I stop the command if stdout contains:
14
+ """
15
+ Hello
16
+ """
17
+
18
+ @sudo
19
+ Scenario: "No controller class is defined" error
20
+ Given a file named "empty.rb" with:
21
+ """
22
+ """
23
+ When I trema run "empty.rb"
24
+ Then the exit status should not be 0
25
+ And the stderr should contain:
26
+ """
27
+ No controller class is defined.
28
+ """
29
+
30
+ @sudo
31
+ Scenario: SyntaxError
32
+ Given a file named "invalid_ruby.rb" with:
33
+ """
34
+ Today is 13 March 2015
35
+ """
36
+ When I run `trema run invalid_ruby.rb`
37
+ And the exit status should not be 0
38
+ Then the output should contain "(SyntaxError)"
39
+
40
+ @sudo
41
+ Scenario: NameError
42
+ Given a file named "invalid_ruby.rb" with:
43
+ """ruby
44
+ class InvalidRuby < Trema::Controller
45
+ Foo
46
+ Bar
47
+ Baz
48
+ end
49
+ """
50
+ When I run `trema run invalid_ruby.rb`
51
+ Then the exit status should not be 0
52
+ And the output should contain "uninitialized constant InvalidRuby::Foo (NameError)"
53
+
54
+ @sudo
55
+ Scenario: RuntimeError
56
+ Given a file named "start_fail.rb" with:
57
+ """ruby
58
+ class StartFail < Trema::Controller
59
+ def start(_args)
60
+ fail 'bang!'
61
+ end
62
+ end
63
+ """
64
+ When I run `trema run start_fail.rb`
65
+ Then the exit status should not be 0
66
+ And the output should contain "bang! (RuntimeError)"
67
+
68
+ @sudo
69
+ Scenario: cleanup on failure
70
+ Given a file named "switch_ready_fail.rb" with:
71
+ """ruby
72
+ class SwitchReadyFail < Trema::Controller
73
+ def switch_ready(_dpid)
74
+ fail 'bang!'
75
+ end
76
+ end
77
+ """
78
+ When I run `trema -v run switch_ready_fail.rb -c trema.conf`
79
+ Then virtual links should not exist
80
+ And the following files should not exist:
81
+ | SwitchReadyFail.pid |
82
+ | vhost.host1.pid |
83
+ | vhost.host2.pid |
@@ -0,0 +1,34 @@
1
+ Feature: -S (--socket_dir) option
2
+
3
+ -S (--socket_dir) option specifies the location to put socket files
4
+
5
+ Background:
6
+ Given a file named "null_controller.rb" with:
7
+ """ruby
8
+ class NullController < Trema::Controller; end
9
+ """
10
+
11
+ @sudo
12
+ Scenario: -S option
13
+ Given a socket directory named "sock"
14
+ When I successfully run `trema run null_controller.rb -S sock -d`
15
+ And I run `sleep 3`
16
+ Then a socket file named "sock/NullController.ctl" should exist
17
+ And a socket file named "sock/trema.NullController.ctl" should exist
18
+
19
+ @sudo
20
+ Scenario: --socket_dir option
21
+ Given a socket directory named "sock"
22
+ When I successfully run `trema run null_controller.rb --socket_dir sock -d`
23
+ And I run `sleep 3`
24
+ Then a socket file named "sock/NullController.ctl" should exist
25
+ And a socket file named "sock/trema.NullController.ctl" should exist
26
+
27
+ @sudo
28
+ Scenario: "No such directory" error
29
+ When I run `trema run null_controller.rb -S sock -d`
30
+ Then the exit status should not be 0
31
+ And the stderr should contain:
32
+ """
33
+ No such directory
34
+ """
@@ -0,0 +1,5 @@
1
+ `trema start` starts the stopped vswitch or vhost again.
2
+
3
+ ```
4
+ trema [global options] start [command options] name
5
+ ```
@@ -0,0 +1,9 @@
1
+ Feature: -S (--socket_dir) option
2
+
3
+ -S (--socket_dir) option specifies the location to find socket files
4
+
5
+ @sudo @wip
6
+ Scenario: -S option
7
+
8
+ @sudo @wip
9
+ Scenario: --socket_dir option
@@ -1,34 +1,34 @@
1
- Feature: trema start command
1
+ Feature: start
2
2
  Background:
3
- Given I set the environment variables to:
4
- | variable | value |
5
- | TREMA_LOG_DIR | . |
6
- | TREMA_PID_DIR | . |
7
- | TREMA_SOCKET_DIR | . |
8
- And a file named "switch_ready_controller.rb" with:
9
- """
3
+ Given a file named "switch_ready_controller.rb" with:
4
+ """ruby
10
5
  class SwitchReadyController < Trema::Controller
6
+ def start(_args)
7
+ @switch_ready_invoked = 0
8
+ end
9
+
11
10
  def switch_ready(dpid)
12
- if @reconnect
11
+ if @switch_ready_invoked > 0
13
12
  logger.info "Switch #{dpid.to_hex} connected again."
14
13
  else
15
14
  logger.info "Switch #{dpid.to_hex} connected."
16
- @reconnect = true
17
15
  end
16
+ @switch_ready_invoked += 1
18
17
  end
19
18
  end
20
19
  """
21
20
  And a file named "trema.conf" with:
22
- """
21
+ """ruby
23
22
  vswitch { datapath_id 0xabc }
24
23
  vhost('host1') { ip '192.168.0.1' }
25
24
  link '0xabc', 'host1'
26
25
  """
27
- And I run `trema run switch_ready_controller.rb -c trema.conf -d`
26
+ And I successfully run `trema run switch_ready_controller.rb -c trema.conf -d`
28
27
 
29
28
  @sudo
30
- Scenario: trema stop and start switch_name
29
+ Scenario: stop and start a switch
31
30
  Given I successfully run `trema stop 0xabc`
31
+ And I successfully run `sleep 3`
32
32
  When I successfully run `trema start 0xabc`
33
33
  And I successfully run `sleep 10`
34
34
  Then the file "SwitchReadyController.log" should contain:
@@ -37,16 +37,15 @@ Feature: trema start command
37
37
  """
38
38
 
39
39
  @sudo
40
- Scenario: trema stop and start host_name
40
+ Scenario: stop and start host_name
41
41
  Given I successfully run `trema stop host1`
42
42
  And I successfully run `sleep 3`
43
43
  When I successfully run `trema start host1`
44
44
  And I successfully run `sleep 10`
45
- Then the following files should exist:
46
- | vhost.host1.pid |
45
+ Then the file named "vhost.host1.pid" should exist
47
46
 
48
47
  @sudo
49
- Scenario: start switch_name (already running)
48
+ Scenario: "Open vSwitch is already running" error
50
49
  When I run `trema start 0xabc`
51
50
  Then the exit status should not be 0
52
51
  And the output should contain:
@@ -54,16 +53,16 @@ Feature: trema start command
54
53
  error: Open vSwitch (dpid = 2748) is already running!
55
54
  """
56
55
 
57
- @sudo
58
- Scenario: start host_name (already running)
56
+ @sudo @wip
57
+ Scenario: "vswitch is already running" error
59
58
  When I run `trema start host1`
60
59
  Then the exit status should not be 0
61
- # And the output should contain:
62
- # """
63
- # error: vhost "host1" is already running!
64
- # """
60
+ And the output should contain:
61
+ """
62
+ error: vhost "host1" is already running!
63
+ """
65
64
 
66
- @sudo
65
+ @sudo @announce-output
67
66
  Scenario: start NO_SUCH_NAME
68
67
  When I run `trema start NO_SUCH_NAME`
69
68
  Then the exit status should not be 0
@@ -0,0 +1,5 @@
1
+ `trema stop` stops a vswitch or a vhost.
2
+
3
+ ```
4
+ trema [global options] stop [command options] name
5
+ ```
@@ -0,0 +1,9 @@
1
+ Feature: -S (--socket_dir) option
2
+
3
+ -S (--socket_dir) option specifies the location to find socket files
4
+
5
+ @sudo @wip
6
+ Scenario: -S option
7
+
8
+ @sudo @wip
9
+ Scenario: --socket_dir option
@@ -1,12 +1,7 @@
1
- Feature: trema stop command
1
+ Feature: stop
2
2
  Background:
3
- Given I set the environment variables to:
4
- | variable | value |
5
- | TREMA_LOG_DIR | . |
6
- | TREMA_PID_DIR | . |
7
- | TREMA_SOCKET_DIR | . |
8
- And a file named "switch_disconnected_controller.rb" with:
9
- """
3
+ Given a file named "switch_disconnected_controller.rb" with:
4
+ """ruby
10
5
  class SwitchDisconnectedController < Trema::Controller
11
6
  def switch_disconnected(dpid)
12
7
  logger.info "Switch #{dpid.to_hex} is disconnected."
@@ -14,7 +9,7 @@ Feature: trema stop command
14
9
  end
15
10
  """
16
11
  And a file named "trema.conf" with:
17
- """
12
+ """ruby
18
13
  vswitch { datapath_id 0xabc }
19
14
 
20
15
  vhost('host1') { ip '192.168.0.1' }
@@ -23,10 +18,10 @@ Feature: trema stop command
23
18
  link '0xabc', 'host1'
24
19
  link '0xabc', 'host2'
25
20
  """
26
- And I run `trema run switch_disconnected_controller.rb -c trema.conf -d`
21
+ And I trema run "switch_disconnected_controller.rb" with the configuration "trema.conf"
27
22
 
28
23
  @sudo
29
- Scenario: stop switch_name
24
+ Scenario: stop a switch
30
25
  When I successfully run `trema stop 0xabc`
31
26
  And I successfully run `sleep 10`
32
27
  Then the file "SwitchDisconnectedController.log" should contain:
@@ -35,7 +30,7 @@ Feature: trema stop command
35
30
  """
36
31
 
37
32
  @sudo
38
- Scenario: stop host_name
33
+ Scenario: stop a host
39
34
  When I successfully run `trema stop host1`
40
35
  And I successfully run `sleep 5`
41
36
  Then the file "vhost.host1.pid" should not exist
data/lib/trema/command.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'English'
2
2
 
3
3
  module Trema
4
+ class InvalidLoggingLevel < StandardError; end
5
+
4
6
  # trema command
5
7
  # rubocop:disable ClassLength
6
8
  class Command
@@ -21,8 +23,19 @@ module Trema
21
23
  @args = args
22
24
  @daemon = options[:daemonize]
23
25
 
24
- Controller.logging_level =
25
- options[:verbose] ? ::Logger::DEBUG : ::Logger::INFO
26
+ begin
27
+ Controller.logging_level =
28
+ { debug: ::Logger::DEBUG,
29
+ info: ::Logger::INFO,
30
+ warn: ::Logger::WARN,
31
+ error: ::Logger::ERROR,
32
+ fatal: ::Logger::FATAL }.fetch(options[:logging_level].to_sym)
33
+ Controller.logging_level = ::Logger::DEBUG if options[:verbose]
34
+ rescue KeyError
35
+ raise(InvalidLoggingLevel,
36
+ "Invalid logging level: #{options[:logging_level]}")
37
+ end
38
+
26
39
  $LOAD_PATH.unshift File.expand_path(File.dirname(@args.first))
27
40
  load @args.first
28
41
  port_number = (options[:port] || Controller::DEFAULT_TCP_PORT).to_i
@@ -7,6 +7,8 @@ require 'trema/logger'
7
7
  require 'trema/monkey_patch/integer'
8
8
 
9
9
  module Trema
10
+ class NoControllerDefined < StandardError; end
11
+
10
12
  # The base class of Trema controller. Subclass and override handlers
11
13
  # to implement a custom OpenFlow controller.
12
14
  #
@@ -134,7 +136,9 @@ module Trema
134
136
 
135
137
  # @private
136
138
  def self.create(port_number = DEFAULT_TCP_PORT)
137
- fail 'No controller class is defined.' unless @controller_klass
139
+ unless @controller_klass
140
+ fail NoControllerDefined, 'No controller class is defined.'
141
+ end
138
142
  @controller_klass.new(port_number)
139
143
  end
140
144
 
@@ -268,8 +272,16 @@ module Trema
268
272
  end
269
273
 
270
274
  def create_and_register_new_switch(socket)
271
- switch = Switch.new(socket).init
275
+ switch = Switch.new(socket)
276
+ switch.init
272
277
  SWITCH[switch.datapath_id] = switch
278
+ rescue Switch::InitError
279
+ error_message = switch.error_message
280
+ case error_message
281
+ when OpenFlow10::Error::HelloFailed, OpenFlow13::Error::HelloFailed
282
+ maybe_send_handler :hello_failed, error_message
283
+ raise $ERROR_INFO
284
+ end
273
285
  end
274
286
 
275
287
  def unregister_switch(datapath_id)
@@ -309,6 +321,8 @@ module Trema
309
321
  else
310
322
  fail "Invalid Port Status message: #{message.inspect}"
311
323
  end
324
+ when Barrier::Reply
325
+ maybe_send_handler :barrier_reply, datapath_id, message
312
326
  else
313
327
  fail "Unknown OpenFlow message: #{message.inspect}"
314
328
  end
data/lib/trema/switch.rb CHANGED
@@ -3,6 +3,10 @@ require 'pio'
3
3
  module Trema
4
4
  # OpenFlow switch.
5
5
  class Switch
6
+ attr_reader :error_message
7
+
8
+ class InitError < StandardError; end
9
+
6
10
  include Pio
7
11
 
8
12
  OPENFLOW_HEADER_LENGTH = 8
@@ -35,51 +39,46 @@ module Trema
35
39
  private
36
40
 
37
41
  def exchange_hello_messages
38
- fail 'Failed to exchange Hello messages' unless read.is_a?(Hello)
39
42
  write Hello.new
43
+ expect_receiving Hello
40
44
  end
41
45
 
42
46
  def exchange_echo_messages
43
47
  write Echo::Request.new
44
- loop do
45
- message = read
46
- if message.is_a?(Echo::Reply)
47
- break
48
- else
49
- handle_early message 'Failed to exchange Echo messages'
50
- end
51
- end
48
+ expect_receiving Echo::Reply
52
49
  end
53
50
 
54
51
  def exchange_features_messages
55
52
  write Features::Request.new
53
+ @features_reply = expect_receiving(Features::Reply)
54
+ end
55
+
56
+ # rubocop:disable MethodLength
57
+ def expect_receiving(expected_message_klass)
56
58
  loop do
57
59
  message = read
58
- if message.is_a?(Features::Reply)
59
- @features_reply = message
60
- break
60
+ case message
61
+ when expected_message_klass
62
+ return message
63
+ when Echo::Request
64
+ write Echo::Reply.new(xid: message.xid)
65
+ when PacketIn, PortStatus # , FlowRemoved (not implemented yet)
66
+ return
67
+ when OpenFlow10::Error::HelloFailed, OpenFlow13::Error::HelloFailed
68
+ @error_message = message
69
+ fail InitError, message.description
61
70
  else
62
- handle_early message 'Failed to exchange Features messages'
71
+ fail "Failed to receive #{expected_message_klass} message"
63
72
  end
64
73
  end
65
74
  end
66
-
67
- def handle_early(message, fail_message)
68
- case message
69
- when Echo::Request
70
- write Echo::Reply.new xid: message.xid
71
- when PacketIn, FlowRemoved, PortStatus
72
- return
73
- else
74
- fail fail_message
75
- end
76
- end
75
+ # rubocop:enable MethodLength
77
76
 
78
77
  def read_openflow_binary
79
78
  header_binary = drain(OPENFLOW_HEADER_LENGTH)
80
79
  header = OpenFlowHeaderParser.read(header_binary)
81
- body_binary = drain(header.message_length - OPENFLOW_HEADER_LENGTH)
82
- fail if (header_binary + body_binary).length != header.message_length
80
+ body_binary = drain(header.length - OPENFLOW_HEADER_LENGTH)
81
+ fail if (header_binary + body_binary).length != header.length
83
82
  header_binary + body_binary
84
83
  end
85
84
 
data/lib/trema/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # Base module.
2
2
  module Trema
3
3
  # gem version.
4
- VERSION = '0.5.1'.freeze
4
+ VERSION = '0.6.0'.freeze
5
5
  end
data/trema.gemspec CHANGED
@@ -22,21 +22,22 @@ Gem::Specification.new do |gem|
22
22
  gem.test_files = `git ls-files -- {spec,features}/*`.split("\n")
23
23
 
24
24
  gem.add_dependency 'bundler', '~> 1.10.6'
25
- gem.add_dependency 'gli', '~> 2.13.1'
26
- gem.add_dependency 'phut', '~> 0.6.6'
27
- gem.add_dependency 'pio', '~> 0.24.1'
25
+ gem.add_dependency 'gli', '~> 2.13.2'
26
+ gem.add_dependency 'phut', '~> 0.6.9'
27
+ gem.add_dependency 'pio', '~> 0.26.0'
28
28
  gem.add_dependency 'rake'
29
29
 
30
30
  # Docs
31
+ gem.add_development_dependency 'relish', '~> 0.7.1'
31
32
  gem.add_development_dependency 'yard', '~> 0.8.7.6'
32
33
 
33
34
  # Test
34
- gem.add_development_dependency 'aruba', '~> 0.8.1'
35
- gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.7'
35
+ gem.add_development_dependency 'aruba', '~> 0.9.0'
36
+ gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.8'
36
37
  gem.add_development_dependency 'coveralls', '~> 0.8.2'
37
38
  gem.add_development_dependency 'cucumber', '~> 2.0.2'
38
- gem.add_development_dependency 'reek', '~> 3.1'
39
+ gem.add_development_dependency 'reek', '~> 3.3.1'
39
40
  gem.add_development_dependency 'rspec', '~> 3.3.0'
40
41
  gem.add_development_dependency 'rspec-given', '~> 3.7.1'
41
- gem.add_development_dependency 'rubocop', '~> 0.32.1'
42
+ gem.add_development_dependency 'rubocop', '~> 0.34.0'
42
43
  end