phut 0.7.7 → 0.7.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|