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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Rakefile +2 -0
- data/bin/trema +17 -2
- data/cucumber.yml +7 -0
- data/features/.nav +47 -0
- data/features/{logging.feature → api/logging.feature} +1 -7
- data/features/{send_flow_mod_add.feature → api/send_flow_mod_add.feature} +2 -7
- data/features/handlers/barrier_reply.feature +30 -0
- data/features/{echo_reply_handler.feature → handlers/echo_reply.feature} +14 -13
- data/features/handlers/hello_failed.feature +56 -0
- data/features/handlers/packet_in.feature +32 -0
- data/features/handlers/start.feature +31 -0
- data/features/handlers/switch_disconnected.feature +34 -0
- data/features/handlers/switch_ready.feature +26 -0
- data/features/logger/debug.feature +41 -0
- data/features/logger/error.feature +41 -0
- data/features/logger/fatal.feature +41 -0
- data/features/logger/info.feature +41 -0
- data/features/logger/warn.feature +41 -0
- data/features/step_definitions/README.txt +2 -0
- data/features/step_definitions/dump_flows_steps.rb +13 -0
- data/features/step_definitions/rest_api_steps.rb +40 -0
- data/features/step_definitions/show_stats_steps.rb +31 -4
- data/features/step_definitions/trema_steps.rb +72 -0
- data/features/support/hooks.rb +4 -1
- data/features/trema_delete_link/README.md +5 -0
- data/features/{trema_delete_link.feature → trema_delete_link/delete_link.feature} +9 -13
- data/features/trema_delete_link/socket_dir_option.feature +12 -0
- data/features/trema_killall/README.md +5 -0
- data/features/trema_killall/all_option.feature +20 -0
- data/features/{trema_killall.feature → trema_killall/killall.feature} +10 -28
- data/features/trema_killall/socket_dir_option.feature +38 -0
- data/features/trema_run/README.md +5 -0
- data/features/trema_run/conf_option.feature +66 -0
- data/features/trema_run/daemonize_option.feature +19 -0
- data/features/trema_run/log_dir_option.feature +32 -0
- data/features/trema_run/logging_level_option.feature +30 -0
- data/features/trema_run/openflow13_option.feature +39 -0
- data/features/trema_run/pid_dir_option.feature +32 -0
- data/features/trema_run/port_option.feature +32 -0
- data/features/trema_run/run.feature +83 -0
- data/features/trema_run/socket_dir_option.feature +34 -0
- data/features/trema_start/README.md +5 -0
- data/features/trema_start/socket_dir_option.feature +9 -0
- data/features/{trema_start.feature → trema_start/start.feature} +23 -24
- data/features/trema_stop/README.md +5 -0
- data/features/trema_stop/socket_dir_option.feature +9 -0
- data/features/{trema_stop.feature → trema_stop/stop.feature} +7 -12
- data/lib/trema/command.rb +15 -2
- data/lib/trema/controller.rb +16 -2
- data/lib/trema/switch.rb +25 -26
- data/lib/trema/version.rb +1 -1
- data/trema.gemspec +8 -7
- metadata +73 -26
- data/features/cleanup_on_failure.feature +0 -118
- data/features/step_definitions/README.md +0 -7
- 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
|
+
"""
|
@@ -1,34 +1,34 @@
|
|
1
|
-
Feature:
|
1
|
+
Feature: start
|
2
2
|
Background:
|
3
|
-
Given
|
4
|
-
|
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 @
|
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:
|
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:
|
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
|
46
|
-
| vhost.host1.pid |
|
45
|
+
Then the file named "vhost.host1.pid" should exist
|
47
46
|
|
48
47
|
@sudo
|
49
|
-
Scenario:
|
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:
|
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
|
-
|
62
|
-
|
63
|
-
|
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
|
@@ -1,12 +1,7 @@
|
|
1
|
-
Feature:
|
1
|
+
Feature: stop
|
2
2
|
Background:
|
3
|
-
Given
|
4
|
-
|
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
|
21
|
+
And I trema run "switch_disconnected_controller.rb" with the configuration "trema.conf"
|
27
22
|
|
28
23
|
@sudo
|
29
|
-
Scenario: stop
|
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
|
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
|
-
|
25
|
-
|
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
|
data/lib/trema/controller.rb
CHANGED
@@ -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
|
-
|
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)
|
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
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
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.
|
82
|
-
fail if (header_binary + body_binary).length != header.
|
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
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.
|
26
|
-
gem.add_dependency 'phut', '~> 0.6.
|
27
|
-
gem.add_dependency 'pio', '~> 0.
|
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.
|
35
|
-
gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.
|
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.
|
42
|
+
gem.add_development_dependency 'rubocop', '~> 0.34.0'
|
42
43
|
end
|