openflow-controller 0.1.9 → 0.1.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 21f97d89fd5cca91d616a17cc08cb2923bc04752
4
- data.tar.gz: f1025ee07213791f7d3472d8b76026a0ac9ba00f
3
+ metadata.gz: f74e50e943f426a39779802e1598be2a3ec7e718
4
+ data.tar.gz: 5bf304ebd253f6dc4978b92db08b4468c0c433f8
5
5
  SHA512:
6
- metadata.gz: 38f589db1750a5395e5b32efa14a249d06b0530c178fcf649a9c5933ae63cba3f1ce9f3b482f996fc979b6e38e017d4c75d5aa551f82aee3ef201c270fa795c0
7
- data.tar.gz: 6ed5c77459538dd5a16fabe2689886a1a6360b41512998f62d284fe2b19f43ea9b843649ea4d3ea2544c2c3a97954be8be898562d85d680692678ae51fe39545
6
+ metadata.gz: ac6728d86881f6aaad177fc65ba88d96b7dc7490cce185f35f13d4c46ee46f70a15cf5c535892f67e4b027ec4b218f7b9ba7aa437ecf751001faa2c4c86c3a2f
7
+ data.tar.gz: 510b7f3df83fc98ed7dbb137f5e8f68278e6b1a2ebf58954624db81c5a4ae1efba98e0d125cd2140abcfbcefb593c0a404d9260164b5945825bfd212ea2c914c
data/bin/ofctl CHANGED
@@ -1,73 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- require 'cri'
3
- require 'readline'
4
2
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
5
- require 'openflow-controller'
6
-
7
- PROMPT = '> '
8
- BYE_MSG = 'Bye!'
9
-
10
- command = Cri::Command.define do
11
- name 'ofctl'
12
- usage 'ofctl [options] [args]'
13
- summary 'OpenFlow Controller command-line tool'
14
- description 'OpenFlow Controller command-line tool'
15
-
16
- flag :h, :help, 'show help for this command' do |value, cmd|
17
- puts cmd.help
18
- exit 0
19
- end
20
- flag :d, :debug, 'run controller in debug mode'
21
-
22
- option :i, :ip, 'IP address of the controller', argument: :optional
23
- option :p, :port, 'port number of the controller', argument: :optional
24
- option :c, :controller, 'custom controller file', argument: :optional
25
-
26
- run do |opts, args, _cmd|
27
- load opts[:controller] unless opts[:controller].nil?
28
-
29
- debug = opts[:debug] || false
30
-
31
- ctl = OpenFlow::Controller::Controller.create(debug)
32
-
33
- init_form = ctl.logger.formatter
34
- ctl.logger.formatter = proc do |severity, datetime, progname, msg|
35
- buf = PROMPT + Readline::line_buffer
36
- "\r" + ' ' * buf.length + "\r" +
37
- init_form.call(severity, datetime, progname, msg).blue +
38
- buf
39
- end
40
-
41
- ip = opts[:ip] || OpenFlow::Controller::Controller::DEFAULT_IP_ADDRESS
42
- port = opts[:port] || OpenFlow::Controller::Controller::DEFAULT_TCP_PORT
43
-
44
- Thread.abort_on_exception = true
45
- Thread.new do
46
- begin
47
- ctl.run ip, port, args
48
- rescue StandardError => e
49
- puts "#{e.class}: #{e.message}".red
50
- exit 1
51
- end
52
- end
53
-
54
- loop do
55
- begin
56
- input = Readline.readline(PROMPT, true)
57
- if input == 'exit'
58
- puts BYE_MSG
59
- exit
60
- end
61
- output = ctl.eval(input).inspect
62
- puts " => #{output}".green
63
- rescue StandardError => e
64
- puts "#{e.class}: #{e.message}".red
65
- rescue SignalException => e
66
- puts "\n#{BYE_MSG}"
67
- exit
68
- end
69
- end
70
- end
71
- end
72
-
73
- command.run(ARGV)
3
+ require 'openflow-controller/cli'
4
+ OpenFlow::Controller::CLI.run
@@ -0,0 +1,95 @@
1
+ require 'cri'
2
+ require 'openflow-controller/completion'
3
+ require 'openflow-controller/controller'
4
+
5
+ module OpenFlow
6
+ module Controller
7
+ class CLI
8
+ PROMPT = '> '
9
+ BYE_MSG = 'Bye!'
10
+
11
+ def self.run
12
+ create_command.run(ARGV)
13
+ end
14
+
15
+ private
16
+
17
+ def self.print_error(e)
18
+ puts "#{e.class}: #{e.message}".red
19
+ puts e.backtrace.join("\n\t").red
20
+ end
21
+
22
+ def self.run_controller_on_thread(ctl, ip, port, args)
23
+ Thread.abort_on_exception = true
24
+ Thread.new do
25
+ begin
26
+ ctl.run ip, port, args
27
+ rescue StandardError => e
28
+ CLI.print_error e
29
+ exit 1
30
+ end
31
+ end
32
+ end
33
+
34
+ def self.run_cli(ctl)
35
+ loop do
36
+ begin
37
+ input = Readline.readline(PROMPT, true)
38
+ if input.nil? || input == 'exit'
39
+ puts if input.nil?
40
+ puts BYE_MSG
41
+ exit
42
+ end
43
+ output = eval(input, ctl.get_binding).inspect
44
+ # output = ctl.eval(input).inspect
45
+ puts " => #{output}".green
46
+ rescue StandardError, SyntaxError => e
47
+ print_error e
48
+ rescue SignalException
49
+ puts
50
+ end
51
+ end
52
+ end
53
+
54
+ def self.create_command
55
+ Cri::Command.define do
56
+ name 'ofctl'
57
+ usage 'ofctl [options] [args]'
58
+ summary 'OpenFlow Controller command-line tool'
59
+ description 'OpenFlow Controller command-line tool'
60
+
61
+ flag :h, :help, 'show help for this command' do |_value, cmd|
62
+ puts cmd.help
63
+ exit 0
64
+ end
65
+ flag :d, :debug, 'run controller in debug mode'
66
+
67
+ option :i, :ip, 'IP address of the controller', argument: :optional
68
+ option :p, :port, 'port number of the controller', argument: :optional
69
+ option :c, :controller, 'custom controller file', argument: :optional
70
+
71
+ run do |opts, args, _cmd|
72
+ load opts[:controller] unless opts[:controller].nil?
73
+
74
+ ctl = Controller.create
75
+ ctl.set_debug if opts[:debug]
76
+
77
+ init_form = ctl.logger.formatter
78
+ ctl.logger.formatter = proc do |severity, datetime, progname, msg|
79
+ buf = PROMPT + Readline::line_buffer
80
+ "\r" + ' ' * buf.length + "\r" +
81
+ init_form.call(severity, datetime, progname, msg).blue +
82
+ buf
83
+ end
84
+
85
+ ip = opts[:ip] || Controller::DEFAULT_IP_ADDRESS
86
+ port = opts[:port] || Controller::DEFAULT_TCP_PORT
87
+
88
+ CLI.run_controller_on_thread ctl, ip, port, args
89
+ CLI.run_cli ctl
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,219 @@
1
+ require 'readline'
2
+ require 'openflow-controller/controller'
3
+
4
+ module OpenFlow
5
+ module Controller
6
+ module Completion
7
+ # Set of reserved words used by Ruby, you should not use these for
8
+ # constants or variables
9
+ RESERVED_WORDS = %w[
10
+ BEGIN END
11
+ alias and
12
+ begin break
13
+ case class
14
+ def defined do
15
+ else elsif end ensure
16
+ false for
17
+ if in
18
+ module
19
+ next nil not
20
+ or
21
+ redo rescue retry return
22
+ self super
23
+ then true
24
+ undef unless until
25
+ when while
26
+ yield
27
+ ]
28
+
29
+ Proc = proc do |input|
30
+ bind = Controller.instance.get_binding
31
+
32
+ case input
33
+ when /^((["'`]).*\2)\.([^.]*)$/
34
+ # String
35
+ receiver = $1
36
+ message = Regexp.quote($3)
37
+
38
+ candidates = String.instance_methods.map(&:to_s)
39
+ select_message(receiver, message, candidates)
40
+
41
+ when /^(\/[^\/]*\/)\.([^.]*)$/
42
+ # Regexp
43
+ receiver = $1
44
+ message = Regexp.quote($2)
45
+
46
+ candidates = Regexp.instance_methods.map(&:to_s)
47
+ select_message(receiver, message, candidates)
48
+
49
+ when /^([^\]]*\])\.([^.]*)$/
50
+ # Array
51
+ receiver = $1
52
+ message = Regexp.quote($2)
53
+
54
+ candidates = Array.instance_methods.map(&:to_s)
55
+ select_message(receiver, message, candidates)
56
+
57
+ when /^([^\}]*\})\.([^.]*)$/
58
+ # Proc or Hash
59
+ receiver = $1
60
+ message = Regexp.quote($2)
61
+
62
+ candidates = Proc.instance_methods.map(&:to_s)
63
+ candidates |= Hash.instance_methods.map(&:to_s)
64
+ select_message(receiver, message, candidates)
65
+
66
+ when /^(:[^:.]*)$/
67
+ # Symbol
68
+ if Symbol.respond_to?(:all_symbols)
69
+ sym = $1
70
+ candidates = Symbol.all_symbols.map { |s| ':' + s.id2name }
71
+ candidates.grep(/^#{Regexp.quote(sym)}/)
72
+ else
73
+ []
74
+ end
75
+
76
+ when /^::([A-Z][^:\.\(]*)$/
77
+ # Absolute Constant or class methods
78
+ receiver = $1
79
+ candidates = Object.constants.map(&:to_s)
80
+ candidates.grep(/^#{receiver}/).map { |s| '::' + s }
81
+
82
+ when /^([A-Z].*)::([^:.]*)$/
83
+ # Constant or class methods
84
+ receiver = $1
85
+ message = Regexp.quote($2)
86
+ begin
87
+ candidates = eval("#{receiver}.constants.map(&:to_s)", bind)
88
+ candidates |= eval("#{receiver}.methods.map(&:to_s)", bind)
89
+ rescue Exception
90
+ candidates = []
91
+ end
92
+ select_message(receiver, message, candidates, '::')
93
+
94
+ when /^(:[^:.]+)(\.|::)([^.]*)$/
95
+ # Symbol
96
+ receiver = $1
97
+ sep = $2
98
+ message = Regexp.quote($3)
99
+
100
+ candidates = Symbol.instance_methods.map(&:to_s)
101
+ select_message(receiver, message, candidates, sep)
102
+
103
+ when /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)(\.|::)([^.]*)$/
104
+ # Numeric
105
+ receiver = $1
106
+ sep = $5
107
+ message = Regexp.quote($6)
108
+
109
+ begin
110
+ candidates = eval(receiver, bind).methods.map(&:to_s)
111
+ rescue Exception
112
+ candidates = []
113
+ end
114
+ select_message(receiver, message, candidates, sep)
115
+
116
+ when /^(-?0x[0-9a-fA-F_]+)(\.|::)([^.]*)$/
117
+ # Numeric(0xFFFF)
118
+ receiver = $1
119
+ sep = $2
120
+ message = Regexp.quote($3)
121
+
122
+ begin
123
+ candidates = eval(receiver, bind).methods.map(&:to_s)
124
+ rescue Exception
125
+ candidates = []
126
+ end
127
+ select_message(receiver, message, candidates, sep)
128
+
129
+ when /^(\$[^.]*)$/
130
+ # global var
131
+ regmessage = Regexp.new(Regexp.quote($1))
132
+ candidates = global_variables.map(&:to_s).grep(regmessage)
133
+
134
+ when /^([^."].*)(\.|::)([^.]*)$/
135
+ # variable.func or func.func
136
+ receiver = $1
137
+ sep = $2
138
+ message = Regexp.quote($3)
139
+
140
+ gv = eval('global_variables', bind).map(&:to_s)
141
+ lv = eval('local_variables', bind).map(&:to_s)
142
+ iv = eval('instance_variables', bind).map(&:to_s)
143
+ cv = eval('self.class.constants', bind).map(&:to_s)
144
+
145
+ if (gv | lv | iv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver
146
+ # foo.func and foo is var. OR
147
+ # foo::func and foo is var. OR
148
+ # foo::Const and foo is var. OR
149
+ # Foo::Bar.func
150
+ begin
151
+ candidates = []
152
+ rec = eval(receiver, bind)
153
+ if sep == '::' and rec.kind_of?(Module)
154
+ candidates = rec.constants.map(&:to_s)
155
+ end
156
+ candidates |= rec.methods.map(&:to_s)
157
+ rescue Exception
158
+ candidates = []
159
+ end
160
+ else
161
+ # func1.func2
162
+ candidates = []
163
+ ObjectSpace.each_object(Module) do |m|
164
+ begin
165
+ name = m.name
166
+ rescue Exception
167
+ name = ''
168
+ end
169
+ begin
170
+ next if name != "IRB::Context" and
171
+ /^(IRB|SLex|RubyLex|RubyToken)/ =~ name
172
+ rescue Exception
173
+ next
174
+ end
175
+ candidates.concat m.instance_methods(false).map(&:to_s)
176
+ end
177
+ candidates.sort!
178
+ candidates.uniq!
179
+ end
180
+ select_message(receiver, message, candidates, sep)
181
+
182
+ when /^\.([^.]*)$/
183
+ # unknown(maybe String)
184
+ receiver = ''
185
+ message = Regexp.quote($1)
186
+
187
+ candidates = String.instance_methods(true).map(&:to_s)
188
+ select_message(receiver, message, candidates)
189
+
190
+ else
191
+ candidates = eval('methods | private_methods | local_variables | instance_variables | self.class.constants | Object.constants | OpenFlow.constants | OpenFlow::Controller.constants', bind).map(&:to_s)
192
+
193
+ (candidates | RESERVED_WORDS).grep(/^#{Regexp.quote(input)}/)
194
+ end
195
+ end
196
+
197
+ # Set of available operators in Ruby
198
+ OPERATORS = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~]
199
+
200
+ def self.select_message(receiver, message, candidates, sep = '.')
201
+ candidates.grep(/^#{message}/).map do |e|
202
+ case e
203
+ when /^[a-zA-Z_]/
204
+ receiver + sep + e
205
+ when /^[0-9]/
206
+ when *OPERATORS
207
+ #receiver + " " + e
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+ if Readline.respond_to?('basic_word_break_characters=')
216
+ Readline.basic_word_break_characters = " \t\n`><=;|&{("
217
+ end
218
+ Readline.completion_append_character = nil
219
+ Readline.completion_proc = OpenFlow::Controller::Completion::Proc
@@ -10,6 +10,7 @@ module OpenFlow
10
10
  module Controller
11
11
  class Controller
12
12
  include Protocol
13
+ include PacketProtocols
13
14
 
14
15
  DEFAULT_IP_ADDRESS = '0.0.0.0'
15
16
  DEFAULT_TCP_PORT = 6633
@@ -18,8 +19,12 @@ module OpenFlow
18
19
  @controller_class = subclass
19
20
  end
20
21
 
21
- def self.create(*args)
22
- (@controller_class || self).new(*args)
22
+ def self.create
23
+ @instance = (@controller_class || self).new
24
+ end
25
+
26
+ def self.instance
27
+ @instance
23
28
  end
24
29
 
25
30
  def self.timer_event(handler, options)
@@ -33,19 +38,23 @@ module OpenFlow
33
38
 
34
39
  attr_reader :logger
35
40
 
36
- def initialize(debug = false)
41
+ def initialize
37
42
  @switches = {}
38
43
  @messages = {}
39
44
  @logger = Logger.new($stdout).tap do |logger|
40
45
  logger.formatter = proc do |severity, datetime, _progname, msg|
41
46
  "#{datetime} (#{severity}) -- #{msg}\n"
42
47
  end
43
- logger.level = debug ? Logger::DEBUG : Logger::INFO
48
+ logger.level = Logger::INFO
44
49
  end
45
50
  end
46
51
 
47
- def eval(input)
48
- binding.eval(input)
52
+ def set_debug
53
+ @logger.level = Logger::DEBUG
54
+ end
55
+
56
+ def get_binding
57
+ binding
49
58
  end
50
59
 
51
60
  def run(ip = DEFAULT_IP_ADDRESS, port = DEFAULT_TCP_PORT, *args)
@@ -1,5 +1,5 @@
1
1
  module OpenFlow
2
2
  module Controller
3
- VERSION = '0.1.9'
3
+ VERSION = '0.1.10'
4
4
  end
5
5
  end
@@ -18,6 +18,7 @@ describe Controller do
18
18
  end
19
19
 
20
20
  it 'should handle start' do
21
+ sleep(0.001)
21
22
  expect(@ctl.start_args).to eq(['Hello World!', 42])
22
23
  end
23
24
 
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
1
3
  require 'openflow-controller'
4
+
2
5
  include OpenFlow::Controller
3
6
  include OpenFlow::Protocol
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openflow-controller
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jérémy Pagé
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-12 00:00:00.000000000 Z
11
+ date: 2016-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: openflow-protocol
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.8
19
+ version: 0.1.9
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.8
26
+ version: 0.1.9
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: colored
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '10.4'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '10.4'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: coveralls
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description: An OpenFlow Controller.
84
98
  email:
85
99
  - contact@jeremypage.me
@@ -90,6 +104,8 @@ extra_rdoc_files: []
90
104
  files:
91
105
  - bin/ofctl
92
106
  - lib/openflow-controller.rb
107
+ - lib/openflow-controller/cli.rb
108
+ - lib/openflow-controller/completion.rb
93
109
  - lib/openflow-controller/controller.rb
94
110
  - lib/openflow-controller/switch.rb
95
111
  - lib/openflow-controller/version.rb