phut 0.7.7 → 0.7.8

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rubocop.yml +14 -1
  4. data/.travis.yml +2 -6
  5. data/Gemfile +30 -2
  6. data/Gemfile.lock +156 -0
  7. data/README.md +7 -2
  8. data/Rakefile +4 -3
  9. data/bin/phut +35 -83
  10. data/bin/vhost +28 -26
  11. data/features/{dsl.feature → dsl/error.feature} +8 -6
  12. data/features/{dsl_link.feature → dsl/link.feature} +11 -14
  13. data/features/dsl/netns.feature +115 -0
  14. data/features/dsl/vhost.feature +37 -0
  15. data/features/{dsl_vswitch.feature → dsl/vswitch.feature} +12 -12
  16. data/features/phut_run.feature +15 -0
  17. data/features/shell/vswitch#destroy.feature +10 -0
  18. data/features/shell/vswitch#ports.feature +36 -0
  19. data/features/shell/vswitch.all.feature +26 -0
  20. data/features/shell/vswitch.create.feature +30 -0
  21. data/features/shell/vswitch.destroy.feature +19 -0
  22. data/features/shell/vswitch.destroy_all.feature +18 -0
  23. data/features/step_definitions/link_steps.rb +5 -0
  24. data/features/step_definitions/netns_steps.rb +31 -0
  25. data/features/step_definitions/phut_steps.rb +5 -34
  26. data/features/step_definitions/vhost_steps.rb +5 -0
  27. data/features/step_definitions/vswitch_steps.rb +17 -0
  28. data/features/support/env.rb +3 -3
  29. data/features/support/hooks.rb +23 -15
  30. data/lib/phut.rb +3 -0
  31. data/lib/phut/finder.rb +19 -0
  32. data/lib/phut/link.rb +84 -0
  33. data/lib/phut/netns.rb +111 -22
  34. data/lib/phut/open_vswitch.rb +98 -96
  35. data/lib/phut/parser.rb +39 -8
  36. data/lib/phut/raw_socket.rb +4 -0
  37. data/lib/phut/route.rb +34 -0
  38. data/lib/phut/setting.rb +21 -4
  39. data/lib/phut/shell_runner.rb +13 -2
  40. data/lib/phut/syntax.rb +31 -14
  41. data/lib/phut/syntax/directive.rb +9 -1
  42. data/lib/phut/syntax/netns_directive.rb +13 -2
  43. data/lib/phut/syntax/vhost_directive.rb +2 -0
  44. data/lib/phut/syntax/vswitch_directive.rb +3 -1
  45. data/lib/phut/version.rb +3 -1
  46. data/lib/phut/veth.rb +68 -0
  47. data/lib/phut/vhost.rb +99 -58
  48. data/lib/phut/vhost_daemon.rb +53 -11
  49. data/lib/phut/vsctl.rb +125 -0
  50. data/lib/phut/vswitch.rb +10 -0
  51. data/phut.gemspec +9 -31
  52. data/tasks/cucumber.rake +5 -1
  53. data/tasks/flay.rake +2 -0
  54. data/tasks/flog.rake +3 -1
  55. data/tasks/gem.rake +2 -0
  56. data/tasks/minitest.rake +7 -0
  57. data/tasks/reek.rake +2 -0
  58. data/tasks/rubocop.rake +2 -0
  59. data/tasks/yard.rake +2 -0
  60. data/test/phut/link_test.rb +85 -0
  61. data/test/phut/netns_test.rb +58 -0
  62. data/test/phut/open_vswitch_test.rb +125 -0
  63. data/test/phut/veth_test.rb +48 -0
  64. data/test/phut/vhost_test.rb +56 -0
  65. metadata +41 -287
  66. data/.rspec +0 -3
  67. data/Guardfile +0 -29
  68. data/features/dsl_vhost.feature +0 -37
  69. data/features/phut_kill.feature +0 -27
  70. data/features/shell.feature +0 -39
  71. data/lib/phut/configuration.rb +0 -92
  72. data/lib/phut/null_logger.rb +0 -14
  73. data/lib/phut/virtual_link.rb +0 -109
  74. data/spec/phut/parser_spec.rb +0 -66
  75. data/spec/phut_spec.rb +0 -45
  76. data/spec/spec_helper.rb +0 -14
  77. data/tasks/LICENSE +0 -675
  78. data/tasks/relish.rake +0 -8
  79. data/tasks/rspec.rake +0 -8
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --require spec_helper
2
- --order random
3
- --color
data/Guardfile DELETED
@@ -1,29 +0,0 @@
1
- guard :rspec, cmd: 'bundle exec rspec' do
2
- watch(%r{^spec/phut/.+_spec\.rb$})
3
- watch(%r{^lib/phut/(.+)\.rb$}) { |m| "spec/phut/#{m[1]}_spec.rb" }
4
- watch('spec/spec_helper.rb') { 'spec' }
5
- end
6
-
7
- guard :bundler do
8
- watch('Gemfile')
9
- watch(/^.+\.gemspec/)
10
- end
11
-
12
- guard :rubocop, all_on_start: false do
13
- watch('Gemfile')
14
- watch('Guardfile')
15
- watch('Rakefile')
16
- watch('bin/phut')
17
- watch(/.+\.rake$/)
18
- watch(/.+\.rb$/)
19
- watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
20
- end
21
-
22
- guard 'cucumber', cli: '--tags ~@sudo --tags ~@shell' do
23
- watch('bin/phut') { 'features' }
24
- watch(%r{^features/.+\.feature$})
25
- watch(%r{^features/support/.+$}) { 'features' }
26
- watch(%r{^features/step_definitions/(.+)_steps\.rb$}) do |m|
27
- Dir[File.join("**/#{m[1]}.feature")][0] || 'features'
28
- end
29
- end
@@ -1,37 +0,0 @@
1
- Feature: The vhost DSL directive.
2
- @sudo
3
- Scenario: phut run with "vhost { ip ... }"
4
- Given a file named "network.conf" with:
5
- """
6
- vhost { ip '192.168.0.1' }
7
- vhost { ip '192.168.0.2' }
8
- link '192.168.0.1', '192.168.0.2'
9
- """
10
- When I do phut run "network.conf"
11
- Then a vhost named "192.168.0.1" launches
12
- And a vhost named "192.168.0.2" launches
13
-
14
- @sudo
15
- Scenario: phut run with "vhost(alias) { ... }"
16
- Given a file named "network.conf" with:
17
- """
18
- vhost('host1') { ip '192.168.0.1' }
19
- vhost('host2') { ip '192.168.0.2' }
20
- link 'host1', 'host2'
21
- """
22
- When I do phut run "network.conf"
23
- Then a vhost named "host1" launches
24
- And a vhost named "host2" launches
25
-
26
- @sudo
27
- Scenario: phut run with "vhost(alias)"
28
- Given a file named "network.conf" with:
29
- """
30
- vhost('host1')
31
- vhost('host2')
32
- link 'host1', 'host2'
33
- """
34
- When I do phut run "network.conf"
35
- Then a vhost named "host1" launches
36
- And a vhost named "host2" launches
37
-
@@ -1,27 +0,0 @@
1
- Feature: phut kill command
2
- Background:
3
- Given a file named "network.conf" with:
4
- """
5
- vswitch { datapath_id 0xabc }
6
-
7
- vhost('host1') { ip '192.168.0.1' }
8
- vhost('host2') { ip '192.168.0.2' }
9
-
10
- link '0xabc', 'host1'
11
- link '0xabc', 'host2'
12
- """
13
- And I do phut run "network.conf"
14
-
15
- @sudo
16
- Scenario: phut kill vswitch_name
17
- When I do phut kill "0xabc"
18
- And I run `sudo ovs-vsctl list-br`
19
- Then the output from "sudo ovs-vsctl list-br" should not contain "br0xabc"
20
-
21
- @sudo
22
- Scenario: phut kill vhost_name
23
- When I do phut kill "host1"
24
- And I successfully run `sleep 5`
25
- Then the following files should not exist:
26
- | vhost.host1.pid |
27
- | vhost.host1.ctl |
@@ -1,39 +0,0 @@
1
- Feature: Shell
2
- Background:
3
- Given I wait 5 seconds for a command to start up
4
- And I run `phut -v` interactively
5
-
6
- @shell
7
- Scenario: vswitch NUMBER
8
- When I type "vswitch 0xabc"
9
- And I type "quit"
10
- And sleep 1
11
- Then a vswitch named "0xabc" should be running
12
-
13
- @shell
14
- Scenario: vswitch STRING
15
- When I type "vswitch '0xabc'"
16
- And I type "quit"
17
- And sleep 1
18
- Then a vswitch named "0xabc" should be running
19
-
20
- @shell
21
- Scenario: vswitch twice and fail
22
- And I type "vswitch 0xabc"
23
- When I type "vswitch 0xabc"
24
- And I type "quit"
25
- Then the output should contain "Open vSwitch (dpid = 0xabc) is already running!"
26
-
27
- @shell
28
- Scenario: Kill and .pid is deleted
29
- And I type "vswitch 0xabc"
30
- When I type "kill 0xabc"
31
- And I type "quit"
32
- And sleep 1
33
- Then a vswitch named "0xabc" should not be running
34
-
35
- @shell
36
- Scenario: Kill without run and fail
37
- When I type "kill 0xabc"
38
- And I type "quit"
39
- Then the output should contain "Open vSwitch (dpid = 0xabc) is not running!"
@@ -1,92 +0,0 @@
1
- require 'phut/null_logger'
2
- require 'phut/open_vswitch'
3
-
4
- module Phut
5
- # Parsed DSL data.
6
- class Configuration
7
- def initialize(&block)
8
- OpenVswitch.all.clear
9
- Vhost.all.clear
10
- Netns.all.clear
11
- VirtualLink.all.clear
12
- block.call self
13
- end
14
-
15
- # rubocop:disable MethodLength
16
- def fetch(key)
17
- case key
18
- when String
19
- [OpenVswitch, Vhost, Netns].each do |each|
20
- found = each.find_by(name: key)
21
- return found if found
22
- end
23
- fail "Invalid key: #{key.inspect}"
24
- when Array
25
- VirtualLink.each do |each|
26
- return each if [each.name_a, each.name_b].sort == key.sort
27
- end
28
- fail "link #{key.join ' '} not found."
29
- else
30
- fail "Invalid key: #{key.inspect}"
31
- end
32
- end
33
- # rubocop:enable MethodLength
34
-
35
- def update_connections
36
- update_vswitch_ports
37
- update_vhost_interfaces
38
- update_netns_interfaces
39
- self
40
- end
41
-
42
- def run
43
- [VirtualLink, Vhost, Netns, OpenVswitch].each do |klass|
44
- klass.each(&:run)
45
- end
46
- end
47
-
48
- def stop
49
- [OpenVswitch, Vhost, Netns, VirtualLink].each do |klass|
50
- klass.each(&:stop)
51
- end
52
- end
53
-
54
- private
55
-
56
- def update_vswitch_ports
57
- VirtualLink.each do |each|
58
- maybe_connect_link_to_vswitch each
59
- end
60
- end
61
-
62
- def maybe_connect_link_to_vswitch(link)
63
- vswitches_connected_to(link).each do |each|
64
- each.add_network_device link.find_network_device(each)
65
- end
66
- end
67
-
68
- def vswitches_connected_to(link)
69
- OpenVswitch.select { |each| link.connect_to?(each) }
70
- end
71
-
72
- def update_vhost_interfaces
73
- Vhost.each do |each|
74
- each.network_device = find_network_device(each)
75
- end
76
- end
77
-
78
- def update_netns_interfaces
79
- Netns.each do |each|
80
- each.network_device = find_network_device(each)
81
- end
82
- end
83
-
84
- def find_network_device(vhost)
85
- VirtualLink.each do |each|
86
- device = each.find_network_device(vhost)
87
- return device if device
88
- end
89
- fail "No network device found for #{vhost}."
90
- end
91
- end
92
- end
@@ -1,14 +0,0 @@
1
- require 'logger'
2
-
3
- module Phut
4
- # Null logger
5
- class NullLogger < Logger
6
- def initialize(*_args)
7
- # noop
8
- end
9
-
10
- def add(*_args, &_block)
11
- # noop
12
- end
13
- end
14
- end
@@ -1,109 +0,0 @@
1
- require 'active_support/core_ext/class/attribute_accessors'
2
- require 'phut/null_logger'
3
- require 'phut/shell_runner'
4
-
5
- module Phut
6
- # Network virtual link.
7
- class VirtualLink
8
- cattr_accessor(:all, instance_reader: false) { [] }
9
-
10
- def self.create(name_a, name_b, logger = NullLogger.new)
11
- new(name_a, name_b, logger).tap { |vlink| all << vlink }
12
- end
13
-
14
- def self.each(&block)
15
- all.each(&block)
16
- end
17
-
18
- # Creates a valid network device name.
19
- class NetworkDeviceName
20
- attr_reader :name
21
- attr_writer :port_number
22
-
23
- def initialize(name)
24
- @name = name
25
- end
26
-
27
- def to_s
28
- @name.tr('.', '_') + port_number_string
29
- end
30
-
31
- def inspect
32
- to_s
33
- end
34
-
35
- private
36
-
37
- def port_number_string
38
- @port_number ? '_' + @port_number.to_s : ''
39
- end
40
- end
41
-
42
- include ShellRunner
43
-
44
- attr_reader :name_a
45
- attr_reader :name_b
46
- attr_reader :device_a
47
- attr_reader :device_b
48
-
49
- def initialize(name_a, name_b, logger)
50
- fail if name_a == name_b
51
- @name_a = name_a
52
- @name_b = name_b
53
- @device_a = NetworkDeviceName.new(name_a)
54
- @device_b = NetworkDeviceName.new(name_b)
55
- @logger = logger
56
- end
57
-
58
- def ==(other)
59
- @name_a == other.name_a &&
60
- @name_b == other.name_b &&
61
- @device_a == other.device_a &&
62
- @device_b == other.device_b
63
- end
64
-
65
- def run
66
- stop if up?
67
- add
68
- up
69
- end
70
-
71
- def stop
72
- return unless up?
73
- stop!
74
- end
75
-
76
- def stop!
77
- sh "sudo ip link delete #{@device_a}"
78
- rescue
79
- raise "link #{@name_a} #{@name_b} does not exist!"
80
- end
81
-
82
- def up?
83
- /^#{@device_a}\s+Link encap:Ethernet/ =~ `LANG=C ifconfig -a` || false
84
- end
85
-
86
- def connect_to?(vswitch)
87
- find_network_device(vswitch) || false
88
- end
89
-
90
- def find_network_device(vswitch_or_vhost)
91
- [@device_a, @device_b].detect do |each|
92
- each.name == vswitch_or_vhost.name
93
- end
94
- end
95
-
96
- private
97
-
98
- def add
99
- sh "sudo ip link add name #{@device_a} type veth peer name #{@device_b}"
100
- sh "sudo /sbin/sysctl -q -w net.ipv6.conf.#{@device_a}.disable_ipv6=1"
101
- sh "sudo /sbin/sysctl -q -w net.ipv6.conf.#{@device_b}.disable_ipv6=1"
102
- end
103
-
104
- def up
105
- sh "sudo /sbin/ifconfig #{@device_a} up"
106
- sh "sudo /sbin/ifconfig #{@device_b} up"
107
- end
108
- end
109
- end
@@ -1,66 +0,0 @@
1
- require 'phut'
2
- require 'stringio'
3
-
4
- describe Phut::Parser do
5
- describe '#parse' do
6
- Given do
7
- allow(IO).to receive(:read).with('CONFIGURATION_FILE').and_return(string)
8
- end
9
- Given(:configuration) { Phut::Parser.new.parse 'CONFIGURATION_FILE' }
10
-
11
- context "with 'vswitch { dpid '0xabc' }'" do
12
- When(:string) { "vswitch { dpid '0xabc' }" }
13
-
14
- describe '#vswitch' do
15
- Then { configuration.fetch('0xabc').datapath_id == 0xabc }
16
- Then { configuration.fetch('0xabc').dpid == 0xabc }
17
- end
18
- end
19
-
20
- context "with 'vswitch { datapath_id '0xabc' }" do
21
- When(:string) { "vswitch { datapath_id '0xabc' }" }
22
-
23
- describe '#vswitch' do
24
- Then { configuration.fetch('0xabc').dpid == 0xabc }
25
- Then { configuration.fetch('0xabc').datapath_id == 0xabc }
26
- end
27
- end
28
-
29
- context "with 'vswitch('my_controller') { dpid '0xabc' }'" do
30
- When(:string) { "vswitch('my_controller') { dpid '0xabc' }" }
31
-
32
- describe '#vswitch' do
33
- Then { configuration.fetch('my_controller').dpid == 0xabc }
34
- Then { configuration.fetch('my_controller').datapath_id == 0xabc }
35
- end
36
- end
37
-
38
- context "with 'vhost { ip '192.168.0.1' }' ..." do
39
- When(:string) do
40
- <<-CONFIGURATION
41
- vhost { ip '192.168.0.1' }
42
- vhost { ip '192.168.0.2' }
43
- link '192.168.0.1', '192.168.0.2'
44
- CONFIGURATION
45
- end
46
-
47
- describe '#vhost' do
48
- Then { configuration.fetch('192.168.0.1').ip_address == '192.168.0.1' }
49
- end
50
- end
51
-
52
- context "with 'vhost('host1') { ip '192.168.0.1' }' ..." do
53
- When(:string) do
54
- <<-CONFIGURATION
55
- vhost('host1') { ip '192.168.0.1' }
56
- vhost('host2') { ip '192.168.0.2' }
57
- link 'host1', 'host2'
58
- CONFIGURATION
59
- end
60
-
61
- describe '#vhost' do
62
- Then { configuration.fetch('host1').ip_address == '192.168.0.1' }
63
- end
64
- end
65
- end
66
- end
@@ -1,45 +0,0 @@
1
- require 'phut/setting'
2
-
3
- describe Phut do
4
- Given { allow(FileTest).to receive(:directory?).and_return(true) }
5
-
6
- describe '.pid_dir' do
7
- Given(:result) { Phut.pid_dir }
8
- Then { result == Dir.tmpdir }
9
-
10
- context "pid_dir = '/tmp/pid'" do
11
- Given { Phut.pid_dir = '/tmp/pid' }
12
- Then { result == '/tmp/pid' }
13
- end
14
-
15
- context "pid_dir = '.'" do
16
- Given { Phut.pid_dir = '.' }
17
- Then { result == File.expand_path('.') }
18
- end
19
- end
20
-
21
- describe '.log_dir' do
22
- Given(:result) { Phut.log_dir }
23
- Then { result == Dir.tmpdir }
24
-
25
- context "log_dir = '/tmp/log'" do
26
- Given { Phut.log_dir = '/tmp/log' }
27
- Then { result == '/tmp/log' }
28
- end
29
-
30
- context "log_dir = '.'" do
31
- Given { Phut.log_dir = '.' }
32
- Then { result == File.expand_path('.') }
33
- end
34
- end
35
-
36
- describe '.socket_dir' do
37
- Given(:result) { Phut.socket_dir }
38
- Then { result == Dir.tmpdir }
39
-
40
- context "socket_dir = '/tmp/socket'" do
41
- Given { Phut.socket_dir = '/tmp/socket' }
42
- Then { result == '/tmp/socket' }
43
- end
44
- end
45
- end