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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.rubocop.yml +14 -1
- data/.travis.yml +2 -6
- data/Gemfile +30 -2
- data/Gemfile.lock +156 -0
- data/README.md +7 -2
- data/Rakefile +4 -3
- data/bin/phut +35 -83
- data/bin/vhost +28 -26
- data/features/{dsl.feature → dsl/error.feature} +8 -6
- data/features/{dsl_link.feature → dsl/link.feature} +11 -14
- data/features/dsl/netns.feature +115 -0
- data/features/dsl/vhost.feature +37 -0
- data/features/{dsl_vswitch.feature → dsl/vswitch.feature} +12 -12
- data/features/phut_run.feature +15 -0
- data/features/shell/vswitch#destroy.feature +10 -0
- data/features/shell/vswitch#ports.feature +36 -0
- data/features/shell/vswitch.all.feature +26 -0
- data/features/shell/vswitch.create.feature +30 -0
- data/features/shell/vswitch.destroy.feature +19 -0
- data/features/shell/vswitch.destroy_all.feature +18 -0
- data/features/step_definitions/link_steps.rb +5 -0
- data/features/step_definitions/netns_steps.rb +31 -0
- data/features/step_definitions/phut_steps.rb +5 -34
- data/features/step_definitions/vhost_steps.rb +5 -0
- data/features/step_definitions/vswitch_steps.rb +17 -0
- data/features/support/env.rb +3 -3
- data/features/support/hooks.rb +23 -15
- data/lib/phut.rb +3 -0
- data/lib/phut/finder.rb +19 -0
- data/lib/phut/link.rb +84 -0
- data/lib/phut/netns.rb +111 -22
- data/lib/phut/open_vswitch.rb +98 -96
- data/lib/phut/parser.rb +39 -8
- data/lib/phut/raw_socket.rb +4 -0
- data/lib/phut/route.rb +34 -0
- data/lib/phut/setting.rb +21 -4
- data/lib/phut/shell_runner.rb +13 -2
- data/lib/phut/syntax.rb +31 -14
- data/lib/phut/syntax/directive.rb +9 -1
- data/lib/phut/syntax/netns_directive.rb +13 -2
- data/lib/phut/syntax/vhost_directive.rb +2 -0
- data/lib/phut/syntax/vswitch_directive.rb +3 -1
- data/lib/phut/version.rb +3 -1
- data/lib/phut/veth.rb +68 -0
- data/lib/phut/vhost.rb +99 -58
- data/lib/phut/vhost_daemon.rb +53 -11
- data/lib/phut/vsctl.rb +125 -0
- data/lib/phut/vswitch.rb +10 -0
- data/phut.gemspec +9 -31
- data/tasks/cucumber.rake +5 -1
- data/tasks/flay.rake +2 -0
- data/tasks/flog.rake +3 -1
- data/tasks/gem.rake +2 -0
- data/tasks/minitest.rake +7 -0
- data/tasks/reek.rake +2 -0
- data/tasks/rubocop.rake +2 -0
- data/tasks/yard.rake +2 -0
- data/test/phut/link_test.rb +85 -0
- data/test/phut/netns_test.rb +58 -0
- data/test/phut/open_vswitch_test.rb +125 -0
- data/test/phut/veth_test.rb +48 -0
- data/test/phut/vhost_test.rb +56 -0
- metadata +41 -287
- data/.rspec +0 -3
- data/Guardfile +0 -29
- data/features/dsl_vhost.feature +0 -37
- data/features/phut_kill.feature +0 -27
- data/features/shell.feature +0 -39
- data/lib/phut/configuration.rb +0 -92
- data/lib/phut/null_logger.rb +0 -14
- data/lib/phut/virtual_link.rb +0 -109
- data/spec/phut/parser_spec.rb +0 -66
- data/spec/phut_spec.rb +0 -45
- data/spec/spec_helper.rb +0 -14
- data/tasks/LICENSE +0 -675
- data/tasks/relish.rake +0 -8
- data/tasks/rspec.rake +0 -8
@@ -0,0 +1,26 @@
|
|
1
|
+
Feature: Vswitch.all
|
2
|
+
Background:
|
3
|
+
Given I run `phut -v` interactively
|
4
|
+
|
5
|
+
@sudo
|
6
|
+
Scenario: Vswitch.all #=> []
|
7
|
+
When I type "Vswitch.all"
|
8
|
+
Then the output should contain "[]"
|
9
|
+
|
10
|
+
@sudo
|
11
|
+
Scenario: Vswitch.all #=> [aVswitch]
|
12
|
+
Given I type "Vswitch.create(name: 'firewall', dpid: 0xabc)"
|
13
|
+
When I type "Vswitch.all"
|
14
|
+
Then the output should contain:
|
15
|
+
"""
|
16
|
+
[#<Vswitch name: "firewall", dpid: 0xabc, openflow_version: 1.0, tcp_port: 6653>]
|
17
|
+
"""
|
18
|
+
|
19
|
+
@sudo
|
20
|
+
Scenario: Vswitch.all #=> [aVswitch]
|
21
|
+
Given I type "Vswitch.create(dpid: 0xabc)"
|
22
|
+
When I type "Vswitch.all"
|
23
|
+
Then the output should contain:
|
24
|
+
"""
|
25
|
+
[#<Vswitch name: "0xabc", dpid: 0xabc, openflow_version: 1.0, tcp_port: 6653>]
|
26
|
+
"""
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Feature: Vswitch.create
|
2
|
+
Background:
|
3
|
+
Given I run `phut -v` interactively
|
4
|
+
|
5
|
+
@sudo
|
6
|
+
Scenario: Vswitch.create(dpid: ...)
|
7
|
+
When I type "Vswitch.create(dpid: 0xabc)"
|
8
|
+
And sleep 5
|
9
|
+
Then a vswitch named "0xabc" should be running
|
10
|
+
|
11
|
+
@sudo
|
12
|
+
Scenario: Vswitch.create(name: ..., dpid: ...)
|
13
|
+
When I type "Vswitch.create(name: 'firewall', dpid: 0xabc)"
|
14
|
+
And sleep 5
|
15
|
+
Then a vswitch named "firewall" should be running
|
16
|
+
|
17
|
+
@sudo
|
18
|
+
Scenario: Vswitch.create(name: ..., dpid: ..., tcp_port:)
|
19
|
+
When I type "vswitch = Vswitch.create(name: 'firewall', dpid: 0xabc, tcp_port: 99999)"
|
20
|
+
And sleep 5
|
21
|
+
Then a vswitch named "firewall" should be running on port "99999"
|
22
|
+
|
23
|
+
@sudo
|
24
|
+
Scenario: Vswitch.create twice and fail
|
25
|
+
Given I type "Vswitch.create(name: 'firewall', dpid: 0xabc)"
|
26
|
+
When I type "Vswitch.create(dpid: 0xabc)"
|
27
|
+
Then the output should contain:
|
28
|
+
"""
|
29
|
+
a Vswitch #<Vswitch name: "firewall", dpid: 0xabc, openflow_version: 1.0, tcp_port: 6653> already exists
|
30
|
+
"""
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Feature: Vswitch.destroy
|
2
|
+
Background:
|
3
|
+
Given I run `phut -v` interactively
|
4
|
+
|
5
|
+
@sudo
|
6
|
+
Scenario: Vswitch.destroy
|
7
|
+
Given I type "Vswitch.create(dpid: 0xabc)"
|
8
|
+
When I type "Vswitch.destroy('0xabc')"
|
9
|
+
And sleep 5
|
10
|
+
Then a vswitch named "0xabc" should not be running
|
11
|
+
|
12
|
+
@sudo
|
13
|
+
Scenario: Vswitch.destroy #=> error
|
14
|
+
When I type "Vswitch.destroy('no_such_switch')"
|
15
|
+
Then the output should contain:
|
16
|
+
"""
|
17
|
+
Vswitch {:name=>"no_such_switch"} not found
|
18
|
+
"""
|
19
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: Vswitch.destroy_all
|
2
|
+
Background:
|
3
|
+
Given I run `phut -v` interactively
|
4
|
+
|
5
|
+
@sudo
|
6
|
+
Scenario: Vswitch.destroy_all
|
7
|
+
When I type "Vswitch.destroy_all"
|
8
|
+
And I type "Vswitch.all"
|
9
|
+
And sleep 5
|
10
|
+
Then the output should contain "[]"
|
11
|
+
|
12
|
+
@sudo
|
13
|
+
Scenario: Vswitch.destroy_all
|
14
|
+
Given I type "Vswitch.create(dpid: 0xabc)"
|
15
|
+
When I type "Vswitch.destroy_all"
|
16
|
+
And I type "Vswitch.all"
|
17
|
+
And sleep 5
|
18
|
+
Then the output should contain "[]"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Then(/^a netns named "(.*?)" should be started$/) do |name|
|
4
|
+
expect(Phut::Netns.find_by!(name: name)).not_to be_nil
|
5
|
+
end
|
6
|
+
|
7
|
+
Then(/^the IP address of the netns "([^"]*)" should not be set$/) do |name|
|
8
|
+
expect(Phut::Netns.find_by!(name: name).ip_address).to be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
Then(/^the IP address of the netns "([^"]*)" should be "([^"]*)"$/) do |name, ip|
|
12
|
+
expect(Phut::Netns.find_by!(name: name).ip_address).to eq ip
|
13
|
+
end
|
14
|
+
|
15
|
+
Then(/^the MAC address of the netns "([^"]*)" should be "([^"]*)"$/) do |name, mac|
|
16
|
+
expect(Phut::Netns.find_by!(name: name).mac_address).to eq mac
|
17
|
+
end
|
18
|
+
|
19
|
+
Then(/^the netmask of the netns "([^"]*)" should be "([^"]*)"$/) do |name, netmask|
|
20
|
+
expect(Phut::Netns.find_by!(name: name).netmask).to eq netmask
|
21
|
+
end
|
22
|
+
|
23
|
+
Then(/^the netns "([^"]*)" have the following route:$/) do |name, table|
|
24
|
+
netns = Phut::Netns.find_by!(name: name)
|
25
|
+
expect(netns.route.net).to eq table.hashes.first['net']
|
26
|
+
expect(netns.route.gateway).to eq table.hashes.first['gateway']
|
27
|
+
end
|
28
|
+
|
29
|
+
Then(/^the VLAN of the netns "([^"]*)" should be "([^"]*)"$/) do |name, vlan|
|
30
|
+
expect(Phut::Netns.find_by!(name: name).vlan).to eq vlan
|
31
|
+
end
|
@@ -1,11 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
When(/^I do phut run "(.*?)"$/) do |config_file|
|
4
|
-
|
5
|
-
|
6
|
-
run_opts = "-P #{@pid_dir} -L #{@log_dir} -S #{@socket_dir}"
|
7
|
-
step %(I run `phut -v run #{run_opts} #{@config_file}`)
|
8
|
-
end
|
4
|
+
run_opts = "-P #{@pid_dir} -L #{@log_dir} -S #{@socket_dir}"
|
5
|
+
step %(I run `phut -v run #{run_opts} #{config_file}`)
|
9
6
|
end
|
10
7
|
|
11
8
|
When(/^I do phut kill "(.*?)"$/) do |name|
|
@@ -13,32 +10,6 @@ When(/^I do phut kill "(.*?)"$/) do |name|
|
|
13
10
|
step %(I successfully run `phut -v kill #{run_opts} #{name}`)
|
14
11
|
end
|
15
12
|
|
16
|
-
When(/^sleep (\d+)$/) do |
|
17
|
-
sleep
|
18
|
-
end
|
19
|
-
|
20
|
-
Then(/^a vswitch named "(.*?)" should be running$/) do |name|
|
21
|
-
expect(system("sudo ovs-vsctl br-exists br#{name}")).to be_truthy
|
22
|
-
end
|
23
|
-
|
24
|
-
# rubocop:disable LineLength
|
25
|
-
Then(/^a vswitch named "([^"]*)" \(controller port = (\d+)\) should be running$/) do |name, port_number|
|
26
|
-
step %(a vswitch named "#{name}" should be running)
|
27
|
-
step %(the output should contain "ovs-vsctl set-controller br#{name} tcp:127.0.0.1:#{port_number}")
|
28
|
-
end
|
29
|
-
# rubocop:enable LineLength
|
30
|
-
|
31
|
-
Then(/^a vswitch named "(.*?)" should not be running$/) do |name|
|
32
|
-
expect(system("sudo ovs-vsctl br-exists br#{name}")).to be_falsey
|
33
|
-
end
|
34
|
-
|
35
|
-
Then(/^a vhost named "(.*?)" launches$/) do |name|
|
36
|
-
step %(a file named "vhost.#{name}.pid" should exist)
|
37
|
-
end
|
38
|
-
|
39
|
-
Then(/^a link is created between "(.*?)" and "(.*?)"$/) do |name_a, name_b|
|
40
|
-
cd('.') do
|
41
|
-
link = Phut::Parser.new.parse(@config_file).fetch([name_a, name_b].sort)
|
42
|
-
expect(link).to be_up
|
43
|
-
end
|
13
|
+
When(/^sleep (\d+)$/) do |second|
|
14
|
+
step "I successfully run `sleep #{second}`"
|
44
15
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Then(/^a vswitch named "([^"]*)" should be running$/) do |name|
|
4
|
+
expect(Phut::Vswitch.find_by(name: name)).not_to be_nil
|
5
|
+
end
|
6
|
+
|
7
|
+
Then(/^a vswitch named "([^"]*)" should be running on port "([^"]*)"$/) do |name, tcp_port|
|
8
|
+
expect(Phut::Vswitch.find_by!(name: name).tcp_port).to eq tcp_port.to_i
|
9
|
+
end
|
10
|
+
|
11
|
+
Then(/^a vswitch named "([^"]*)" should not be running$/) do |name|
|
12
|
+
expect(Phut::Vswitch.find_by(name: name)).to be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
Then(/^a vswitch named "([^"]*)" \(controller port = (\d+)\) should be running$/) do |name, port_number|
|
16
|
+
expect(Phut::Vswitch.find_by!(name: name).tcp_port).to eq port_number.to_i
|
17
|
+
end
|
data/features/support/env.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
3
|
+
require 'aruba/cucumber'
|
4
|
+
require 'phut'
|
data/features/support/hooks.rb
CHANGED
@@ -1,13 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'phut'
|
2
4
|
|
3
5
|
Before do
|
4
|
-
|
5
|
-
|
6
|
-
|
6
|
+
Aruba.configure do |config|
|
7
|
+
Dir.chdir(config.working_directory) do
|
8
|
+
@log_dir = './log'
|
9
|
+
@pid_dir = './tmp/pids'
|
10
|
+
@socket_dir = './tmp/sockets'
|
11
|
+
|
12
|
+
FileUtils.mkdir_p(@log_dir) unless File.exist?(@log_dir)
|
13
|
+
FileUtils.mkdir_p(@pid_dir) unless File.exist?(@pid_dir)
|
14
|
+
FileUtils.mkdir_p(@socket_dir) unless File.exist?(@socket_dir)
|
15
|
+
|
16
|
+
Phut.pid_dir = @pid_dir
|
17
|
+
Phut.log_dir = @log_dir
|
18
|
+
Phut.socket_dir = @socket_dir
|
19
|
+
end
|
20
|
+
end
|
7
21
|
end
|
8
22
|
|
9
23
|
Before('@sudo') do
|
10
|
-
|
24
|
+
raise 'sudo authentication failed' unless system 'sudo -v'
|
11
25
|
@aruba_timeout_seconds = 10
|
12
26
|
end
|
13
27
|
|
@@ -17,17 +31,11 @@ After('@sudo') do
|
|
17
31
|
Phut.pid_dir = @pid_dir
|
18
32
|
Phut.log_dir = @log_dir
|
19
33
|
Phut.socket_dir = @socket_dir
|
20
|
-
Phut::Parser.new.parse(@config_file).stop
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
Before('@shell') do
|
26
|
-
fail 'sudo authentication failed' unless system 'sudo -v'
|
27
|
-
end
|
28
34
|
|
29
|
-
|
30
|
-
|
31
|
-
|
35
|
+
Phut::Vswitch.destroy_all
|
36
|
+
Phut::Vhost.destroy_all
|
37
|
+
Phut::Netns.destroy_all
|
38
|
+
Phut::Link.destroy_all
|
39
|
+
end
|
32
40
|
end
|
33
41
|
end
|
data/lib/phut.rb
CHANGED
data/lib/phut/finder.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
4
|
+
|
5
|
+
module Phut
|
6
|
+
# Defines find_by method
|
7
|
+
module Finder
|
8
|
+
def find_by(queries)
|
9
|
+
queries.inject(all) do |memo, (attr, value)|
|
10
|
+
memo.find_all { |each| each.__send__(attr) == value }
|
11
|
+
end.first
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_by!(queries)
|
15
|
+
name = to_s.demodulize
|
16
|
+
find_by(queries) || raise("#{name} #{queries.inspect} not found")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/phut/link.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'phut/netns'
|
4
|
+
require 'phut/shell_runner'
|
5
|
+
require 'phut/veth'
|
6
|
+
|
7
|
+
module Phut
|
8
|
+
# Virtual link
|
9
|
+
class Link
|
10
|
+
def self.all
|
11
|
+
link = Hash.new { [] }
|
12
|
+
Veth.all.each { |each| link[each.link_id] += [each.name] }
|
13
|
+
link.map { |link_id, names| new(names.first, names.second, link_id) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find(end1, end2)
|
17
|
+
all.find { |each| each.ends.map(&:name) == [end1, end2].map(&:to_s).sort }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.create(end1, end2)
|
21
|
+
new(end1, end2).start
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.destroy_all
|
25
|
+
all.each(&:destroy)
|
26
|
+
end
|
27
|
+
|
28
|
+
include ShellRunner
|
29
|
+
|
30
|
+
attr_reader :ends
|
31
|
+
|
32
|
+
def initialize(name1, name2, link_id = Link.all.size)
|
33
|
+
raise if name1 == name2
|
34
|
+
@ends = [Veth.new(name: name1, link_id: link_id),
|
35
|
+
Veth.new(name: name2, link_id: link_id)].sort
|
36
|
+
end
|
37
|
+
|
38
|
+
def start
|
39
|
+
return self if up?
|
40
|
+
add
|
41
|
+
up
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def destroy
|
46
|
+
sudo "ip link delete #{end1} || true"
|
47
|
+
sudo "ip link delete #{end2} || true"
|
48
|
+
end
|
49
|
+
alias stop destroy
|
50
|
+
|
51
|
+
def device(name)
|
52
|
+
ends.find { |each| each.name == name.to_s }
|
53
|
+
end
|
54
|
+
|
55
|
+
def ==(other)
|
56
|
+
ends == other.ends
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def end1
|
62
|
+
ends.first
|
63
|
+
end
|
64
|
+
|
65
|
+
def end2
|
66
|
+
ends.second
|
67
|
+
end
|
68
|
+
|
69
|
+
def add
|
70
|
+
sudo "ip link add name #{end1.device} type veth peer name #{end2.device}"
|
71
|
+
sudo "/sbin/sysctl -q -w net.ipv6.conf.#{end1.device}.disable_ipv6=1"
|
72
|
+
sudo "/sbin/sysctl -q -w net.ipv6.conf.#{end2.device}.disable_ipv6=1"
|
73
|
+
end
|
74
|
+
|
75
|
+
def up?
|
76
|
+
Link.all.include? self
|
77
|
+
end
|
78
|
+
|
79
|
+
def up
|
80
|
+
sudo "/sbin/ifconfig #{end1.device} up"
|
81
|
+
sudo "/sbin/ifconfig #{end2.device} up"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/phut/netns.rb
CHANGED
@@ -1,48 +1,137 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'phut/finder'
|
4
|
+
require 'phut/route'
|
3
5
|
require 'phut/shell_runner'
|
6
|
+
require 'phut/veth'
|
4
7
|
|
5
8
|
module Phut
|
6
9
|
# `ip netns ...` command runner
|
7
10
|
class Netns
|
8
|
-
|
11
|
+
extend ShellRunner
|
12
|
+
extend Finder
|
13
|
+
|
14
|
+
# rubocop:disable MethodLength
|
15
|
+
# rubocop:disable AbcSize
|
16
|
+
def self.all
|
17
|
+
sh('ip netns list').split("\n").map do |each|
|
18
|
+
name = each.split.first
|
19
|
+
ip_addr_list =
|
20
|
+
sudo("ip netns exec #{name} ip -4 -o addr list").split("\n")
|
21
|
+
mac_addr_list =
|
22
|
+
sudo("ip netns exec #{name} ip -4 -o link list").split("\n")
|
23
|
+
if ip_addr_list.size > 1
|
24
|
+
%r{inet ([^/]+)/(\d+)} =~ ip_addr_list[1]
|
25
|
+
ip_address = Regexp.last_match(1)
|
26
|
+
mask_length = Regexp.last_match(2).to_i
|
27
|
+
netmask = IPAddr.new('255.255.255.255').mask(mask_length).to_s
|
28
|
+
%r{link/ether ((?:[a-f\d]{2}:){5}[a-f\d]{2})}i =~ mac_addr_list[1]
|
29
|
+
new(name: name, ip_address: ip_address, netmask: netmask,
|
30
|
+
mac_address: Regexp.last_match(1))
|
31
|
+
else
|
32
|
+
new(name: name)
|
33
|
+
end
|
34
|
+
end.sort_by(&:name)
|
35
|
+
end
|
36
|
+
# rubocop:enable MethodLength
|
37
|
+
# rubocop:enable AbcSize
|
9
38
|
|
10
|
-
def self.create(
|
11
|
-
new(
|
39
|
+
def self.create(*args)
|
40
|
+
new(*args).tap(&:run)
|
12
41
|
end
|
13
42
|
|
14
|
-
def self.
|
15
|
-
all.each(
|
43
|
+
def self.destroy_all
|
44
|
+
all.each(&:stop)
|
16
45
|
end
|
17
46
|
|
18
47
|
include ShellRunner
|
19
48
|
|
20
49
|
attr_reader :name
|
21
|
-
|
50
|
+
attr_reader :ip_address
|
51
|
+
attr_reader :mac_address
|
22
52
|
|
23
|
-
|
53
|
+
# rubocop:disable ParameterLists
|
54
|
+
def initialize(name:,
|
55
|
+
ip_address: nil,
|
56
|
+
mac_address: nil,
|
57
|
+
netmask: '255.255.255.255',
|
58
|
+
route: {},
|
59
|
+
vlan: nil)
|
24
60
|
@name = name
|
25
|
-
@
|
26
|
-
@
|
61
|
+
@ip_address = ip_address
|
62
|
+
@mac_address = mac_address
|
63
|
+
@netmask = netmask
|
64
|
+
@route = Route.new(net: route[:net], gateway: route[:gateway])
|
65
|
+
@vlan = vlan
|
27
66
|
end
|
67
|
+
# rubocop:enable MethodLength
|
68
|
+
# rubocop:enable ParameterLists
|
28
69
|
|
29
|
-
# rubocop:disable AbcSize
|
30
70
|
def run
|
31
|
-
|
32
|
-
|
33
|
-
sh "sudo ip netns exec #{name} ifconfig lo 127.0.0.1"
|
34
|
-
sh "sudo ip netns exec #{name}"\
|
35
|
-
" ifconfig #{network_device} #{ip} netmask #{netmask}"
|
36
|
-
sh "sudo ip netns exec #{name} route add -net #{net} gw #{gateway}"
|
71
|
+
sudo "ip netns add #{name}"
|
72
|
+
sudo "ip netns exec #{name} ifconfig lo 127.0.0.1"
|
37
73
|
end
|
38
|
-
# rubocop:enable AbcSize
|
39
74
|
|
40
75
|
def stop
|
41
|
-
|
76
|
+
sudo("ip netns pids #{name}").split("\n").each do |each|
|
77
|
+
exec "kill #{each}"
|
78
|
+
end
|
79
|
+
sudo "ip netns delete #{name}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def exec(command)
|
83
|
+
sudo "ip netns exec #{name} #{command}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def device
|
87
|
+
return unless /^\d+: #{Veth::PREFIX}(\d+)_([^:\.]*?)[@:]/ =~
|
88
|
+
sudo("ip netns exec #{name} ip -o link show")
|
89
|
+
Veth.new(name: $LAST_MATCH_INFO[2], link_id: $LAST_MATCH_INFO[1].to_i)
|
90
|
+
end
|
91
|
+
|
92
|
+
# rubocop:disable MethodLength
|
93
|
+
# rubocop:disable AbcSize
|
94
|
+
def device=(veth)
|
95
|
+
sudo "ip link set dev #{veth} netns #{name}"
|
96
|
+
|
97
|
+
vlan_suffix = @vlan ? ".#{@vlan}" : ''
|
98
|
+
if @vlan
|
99
|
+
sudo "ip netns exec #{name} ip link set #{veth} up"
|
100
|
+
sudo "ip netns exec #{name} "\
|
101
|
+
"ip link add link #{veth} name "\
|
102
|
+
"#{veth}#{vlan_suffix} type vlan id #{@vlan}"
|
103
|
+
end
|
104
|
+
if @mac_address
|
105
|
+
sudo "ip netns exec #{name} "\
|
106
|
+
"ip link set #{veth}#{vlan_suffix} address #{@mac_address}"
|
107
|
+
end
|
108
|
+
sudo "ip netns exec #{name} ip link set #{veth}#{vlan_suffix} up"
|
109
|
+
sudo "ip netns exec #{name} "\
|
110
|
+
"ip addr replace #{@ip_address}/#{@netmask} "\
|
111
|
+
"dev #{veth}#{vlan_suffix}"
|
112
|
+
sudo "ip netns exec #{name} ip link set #{veth}#{vlan_suffix} up"
|
113
|
+
|
114
|
+
@route.add name
|
115
|
+
end
|
116
|
+
# rubocop:enable MethodLength
|
117
|
+
# rubocop:enable AbcSize
|
118
|
+
|
119
|
+
def netmask
|
120
|
+
if %r{inet [^/]+/(\d+) } =~
|
121
|
+
sudo("ip netns exec #{name} ip -o -4 address show dev #{device}")
|
122
|
+
IPAddr.new('255.255.255.255').mask(Regexp.last_match(1).to_i).to_s
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def route
|
127
|
+
Route.read name
|
42
128
|
end
|
43
129
|
|
44
|
-
def
|
45
|
-
|
130
|
+
def vlan
|
131
|
+
if /^\d+: #{device.device}\.(\d+)@/ =~
|
132
|
+
sudo("ip netns exec #{name} ip -o link show")
|
133
|
+
Regexp.last_match(1)
|
134
|
+
end
|
46
135
|
end
|
47
136
|
end
|
48
137
|
end
|