From 74c751bcb466100350f48760fd85595bb59b3480 Mon Sep 17 00:00:00 2001 From: Hiroshi Ota Date: Tue, 24 May 2016 08:48:16 +0900 Subject: [PATCH 1/4] Add test scenario for Netns DSL --- features/dsl_netns.feature | 44 +++++++++++++++++++++++++ features/step_definitions/phut_steps.rb | 18 ++++++++++ 2 files changed, 62 insertions(+) create mode 100644 features/dsl_netns.feature diff --git a/features/dsl_netns.feature b/features/dsl_netns.feature new file mode 100644 index 0000000..3ae0c19 --- /dev/null +++ b/features/dsl_netns.feature @@ -0,0 +1,44 @@ +Feature: The netns DSL directive. + @sudo + Scenario: phut run with "netns(alias) { ip ... }" + Given a file named "network.conf" with: + """ + netns('host1') { + ip '192.168.8.6' + } + netns('host2') { + ip '192.168.8.7' + } + link 'host1', 'host2' + """ + When I do phut run "network.conf" + Then a netns named "host1" launches + And "netmask" is "/24" in netns "host1" + And "default_gateway" is "" in netns "host1" + And a netns named "host2" launches + And "netmask" is "/24" in netns "host2" + And "default_gateway" is "" in netns "host2" + + @sudo + Scenario: phut run with "netns(alias) { ip, netmask, route ... }" + Given a file named "network.conf" with: + """ + netns('host1') { + ip '192.168.8.6' + netmask '255.255.255.128' + route net: '0.0.0.0/0', gateway: '192.168.8.1' + } + netns('host2') { + ip '192.168.8.7' + netmask '255.255.255.128' + route net: '0.0.0.0/0', gateway: '192.168.8.1' + } + link 'host1', 'host2' + """ + When I do phut run "network.conf" + Then a netns named "host1" launches + And "netmask" is "/25" in netns "host1" + And "default_gateway" is "192.168.8.1" in netns "host1" + And a netns named "host2" launches + And "netmask" is "/25" in netns "host2" + And "default_gateway" is "192.168.8.1" in netns "host2" diff --git a/features/step_definitions/phut_steps.rb b/features/step_definitions/phut_steps.rb index cd26eb2..399ddca 100644 --- a/features/step_definitions/phut_steps.rb +++ b/features/step_definitions/phut_steps.rb @@ -36,6 +36,24 @@ step %(a file named "vhost.#{name}.pid" should exist) end +Then(/^a netns named "(.*?)" launches$/) do |name| + expect(`ip netns`).to match(/^#{name}$/) +end + +Then(/"(.*?)" is "(.*?)" in netns "(.*?)"/) do |key, value, netns| + command = + case key + when 'netmask' + "ip addr list dev #{netns} | grep inet" + when 'default_gateway' + 'ip route list match 0/0' + else + 'ip link list ; ip addr list' + end + + expect(`sudo ip netns exec #{netns} #{command}`).to match(/#{value}/) +end + Then(/^a link is created between "(.*?)" and "(.*?)"$/) do |name_a, name_b| cd('.') do link = Phut::Parser.new.parse(@config_file).fetch([name_a, name_b].sort) From aba5739ac93c95decdd846882e2ace5b1e3e7326 Mon Sep 17 00:00:00 2001 From: Hiroshi Ota Date: Tue, 24 May 2016 22:15:55 +0900 Subject: [PATCH 2/4] Allow simple configuration without netmask nor routing --- lib/phut/netns.rb | 3 ++- lib/phut/syntax/netns_directive.rb | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/phut/netns.rb b/lib/phut/netns.rb index b9561d6..263cf01 100644 --- a/lib/phut/netns.rb +++ b/lib/phut/netns.rb @@ -33,7 +33,8 @@ def run sh "sudo ip netns exec #{name} ifconfig lo 127.0.0.1" sh "sudo ip netns exec #{name}"\ " ifconfig #{network_device} #{ip} netmask #{netmask}" - sh "sudo ip netns exec #{name} route add -net #{net} gw #{gateway}" + sh "sudo ip netns exec #{name}"\ + " route add -net #{net} gw #{gateway}" if gateway end # rubocop:enable AbcSize diff --git a/lib/phut/syntax/netns_directive.rb b/lib/phut/syntax/netns_directive.rb index d32d17b..98bf7f7 100644 --- a/lib/phut/syntax/netns_directive.rb +++ b/lib/phut/syntax/netns_directive.rb @@ -7,7 +7,11 @@ class NetnsDirective < Directive attribute :netmask def initialize(alias_name, &block) - @attributes = { name: alias_name } + @attributes = + { name: alias_name, + netmask: '255.255.255.0', + net: '0.0.0.0', + gateway: nil } instance_eval(&block) end From a023b5618cf4a30ecedc715b96933398abd92293 Mon Sep 17 00:00:00 2001 From: Hiroshi Ota Date: Fri, 27 May 2016 22:36:57 +0900 Subject: [PATCH 3/4] Add MAC address and VLAN configuration --- features/dsl_netns.feature | 56 +++++++++++++++++++++---- features/step_definitions/phut_steps.rb | 6 ++- lib/phut/netns.rb | 44 ++++++++++++++++--- lib/phut/syntax/netns_directive.rb | 12 +++++- 4 files changed, 102 insertions(+), 16 deletions(-) diff --git a/features/dsl_netns.feature b/features/dsl_netns.feature index 3ae0c19..5bdd1b8 100644 --- a/features/dsl_netns.feature +++ b/features/dsl_netns.feature @@ -13,11 +13,11 @@ Feature: The netns DSL directive. """ When I do phut run "network.conf" Then a netns named "host1" launches - And "netmask" is "/24" in netns "host1" - And "default_gateway" is "" in netns "host1" + And the "netmask" of the netns "host1" should be "/24" + And the "default_gateway" of the netns "host1" should be "" And a netns named "host2" launches - And "netmask" is "/24" in netns "host2" - And "default_gateway" is "" in netns "host2" + And the "netmask" of the netns "host2" should be "/24" + And the "default_gateway" of the netns "host2" should be "" @sudo Scenario: phut run with "netns(alias) { ip, netmask, route ... }" @@ -37,8 +37,48 @@ Feature: The netns DSL directive. """ When I do phut run "network.conf" Then a netns named "host1" launches - And "netmask" is "/25" in netns "host1" - And "default_gateway" is "192.168.8.1" in netns "host1" + And the "netmask" of the netns "host1" should be "/25" + And the "default_gateway" of the netns "host1" should be "192.168.8.1" And a netns named "host2" launches - And "netmask" is "/25" in netns "host2" - And "default_gateway" is "192.168.8.1" in netns "host2" + And the "netmask" of the netns "host2" should be "/25" + And the "default_gateway" of the netns "host2" should be "192.168.8.1" + + @sudo + Scenario: phut run with "netns(alias) { ip, vlan }" + Given a file named "network.conf" with: + """ + netns('host1') { + ip '192.168.8.6' + vlan 10 + } + netns('host2') { + ip '192.168.8.7' + vlan 20 + } + link 'host1', 'host2' + """ + When I do phut run "network.conf" + Then a netns named "host1" launches + And the "vlan" of the netns "host1" should be "10" + And a netns named "host2" launches + And the "vlan" of the netns "host2" should be "20" + + @sudo + Scenario: phut run with "netns(alias) { ip, mac }" + Given a file named "network.conf" with: + """ + netns('host1') { + ip '192.168.8.6' + mac '00:53:00:00:00:01' + } + netns('host2') { + ip '192.168.8.7' + mac '00:53:00:00:00:02' + } + link 'host1', 'host2' + """ + When I do phut run "network.conf" + Then a netns named "host1" launches + And the "mac" of the netns "host1" should be "00:53:00:00:00:01" + And a netns named "host2" launches + And the "mac" of the netns "host2" should be "00:53:00:00:00:02" diff --git a/features/step_definitions/phut_steps.rb b/features/step_definitions/phut_steps.rb index 399ddca..13e745d 100644 --- a/features/step_definitions/phut_steps.rb +++ b/features/step_definitions/phut_steps.rb @@ -40,19 +40,23 @@ expect(`ip netns`).to match(/^#{name}$/) end -Then(/"(.*?)" is "(.*?)" in netns "(.*?)"/) do |key, value, netns| +# rubocop:disable LineLength +Then(/^the "(.*?)" of the netns "(.*?)" should be "(.*?)"$/) do |key, netns, value| command = case key when 'netmask' "ip addr list dev #{netns} | grep inet" when 'default_gateway' 'ip route list match 0/0' + when 'vlan' + "ip link list dev #{netns}.#{value}" else 'ip link list ; ip addr list' end expect(`sudo ip netns exec #{netns} #{command}`).to match(/#{value}/) end +# rubocop:enable LineLength Then(/^a link is created between "(.*?)" and "(.*?)"$/) do |name_a, name_b| cd('.') do diff --git a/lib/phut/netns.rb b/lib/phut/netns.rb index 263cf01..ced58fc 100644 --- a/lib/phut/netns.rb +++ b/lib/phut/netns.rb @@ -26,20 +26,52 @@ def initialize(options, name, logger) @logger = logger end - # rubocop:disable AbcSize def run + setup_netns + setup_link + setup_ip + end + + def stop + sh "sudo ip netns delete #{name}" + end + + private + + def setup_netns sh "sudo ip netns add #{name}" sh "sudo ip link set dev #{network_device} netns #{name}" + end + + def setup_link + setup_vlan + setup_mac_address + end + + def setup_vlan + return unless vlan + sh "sudo ip netns exec #{name}"\ + " ifconfig #{network_device} up" + sh "sudo ip netns exec #{name}"\ + " ip link add link #{network_device} name"\ + " #{network_device}#{vlan_suffix} type vlan id #{vlan}" + end + + def setup_mac_address + sh "sudo ip netns exec #{name}"\ + " ip link set #{network_device}#{vlan_suffix} address #{mac}" if mac + end + + def setup_ip sh "sudo ip netns exec #{name} ifconfig lo 127.0.0.1" sh "sudo ip netns exec #{name}"\ - " ifconfig #{network_device} #{ip} netmask #{netmask}" + " ifconfig #{network_device}#{vlan_suffix} #{ip} netmask #{netmask}" sh "sudo ip netns exec #{name}"\ - " route add -net #{net} gw #{gateway}" if gateway + " route add -net #{net} gw #{gateway}" if gateway end - # rubocop:enable AbcSize - def stop - sh "sudo ip netns delete #{name}" + def vlan_suffix + vlan ? ".#{vlan}" : '' end def method_missing(message, *_args) diff --git a/lib/phut/syntax/netns_directive.rb b/lib/phut/syntax/netns_directive.rb index 98bf7f7..7a7c4dc 100644 --- a/lib/phut/syntax/netns_directive.rb +++ b/lib/phut/syntax/netns_directive.rb @@ -11,7 +11,9 @@ def initialize(alias_name, &block) { name: alias_name, netmask: '255.255.255.0', net: '0.0.0.0', - gateway: nil } + gateway: nil, + mac: nil, + vlan: nil } instance_eval(&block) end @@ -24,6 +26,14 @@ def route(options) @attributes[:net] = options.fetch(:net) @attributes[:gateway] = options.fetch(:gateway) end + + def mac(value) + @attributes[:mac] = value + end + + def vlan(value) + @attributes[:vlan] = value + end end end end From f89696424b3a3e9fb4c49aa4c650cc75dfced649 Mon Sep 17 00:00:00 2001 From: Hiroshi Ota Date: Sat, 28 May 2016 20:50:44 +0900 Subject: [PATCH 4/4] Replace ifconfig/route command with ip command --- lib/phut/netns.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/phut/netns.rb b/lib/phut/netns.rb index ced58fc..99a3ec1 100644 --- a/lib/phut/netns.rb +++ b/lib/phut/netns.rb @@ -46,12 +46,15 @@ def setup_netns def setup_link setup_vlan setup_mac_address + sh "sudo ip netns exec #{name} ip link set lo up" + sh "sudo ip netns exec #{name}"\ + " ip link set #{network_device}#{vlan_suffix} up" end def setup_vlan return unless vlan sh "sudo ip netns exec #{name}"\ - " ifconfig #{network_device} up" + " ip link set #{network_device} up" sh "sudo ip netns exec #{name}"\ " ip link add link #{network_device} name"\ " #{network_device}#{vlan_suffix} type vlan id #{vlan}" @@ -63,11 +66,11 @@ def setup_mac_address end def setup_ip - sh "sudo ip netns exec #{name} ifconfig lo 127.0.0.1" + sh "sudo ip netns exec #{name} ip addr replace 127.0.0.1 dev lo" sh "sudo ip netns exec #{name}"\ - " ifconfig #{network_device}#{vlan_suffix} #{ip} netmask #{netmask}" + " ip addr replace #{ip}/#{netmask} dev #{network_device}#{vlan_suffix}" sh "sudo ip netns exec #{name}"\ - " route add -net #{net} gw #{gateway}" if gateway + " ip route add #{net} via #{gateway}" if gateway end def vlan_suffix