Prepare network_checker for ci
Vagrant will spawn virtualbox vm with 3 interfaces with 2 of them in same network (which will be handy for some debug) eth1 and eth2 will be controlled by dhcp server in same network This approach has couple of requirements: 1. virtualbox installed on jenkins node 2. vagrant installed on jenkins node 3. added precise64 box for vagrant vagrant up - will create vm and install all necessery packages to run tests: vagrant ssh -c 'sudo py.test /vagrant/' will run tests for network_checker and dhcpchecker exit status will be non-zero in case of errors sudo is required for capturing data on ifaces To make docker approach to work: 1. Share linux drivers for docker containter (netchecker uses modprobe 8021q) 2. setup dnsmasq on same bridge which this docker image is using Tests can be started on local machine with help of vde switch: py.test --vde ./ This will create vde_switch and tap ifaces (tap11, tap12) Related to blueprint fuel-network-checks-ci Change-Id: Ieefca56f31db988a610870710ec9cb0ad1a0d6a6
This commit is contained in:
parent
3df411acf2
commit
34995c649a
10
network_checker/Dockerfile
Normal file
10
network_checker/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
||||
FROM phusion/baseimage
|
||||
ENV ARCH amd64
|
||||
ENV DIST precise
|
||||
RUN echo 'deb http://fuel-repository.mirantis.com/fwm/5.0/ubuntu precise main' >> /etc/apt/sources.list
|
||||
RUN apt-get -q update
|
||||
RUN apt-get -y --force-yes install cliff-tablib python-pyparsing python-pypcap scapy python-pip wget openssh-server
|
||||
RUN pip install pytest mock
|
||||
RUN sudo locale-gen en_US.UTF-8
|
||||
|
||||
RUN mkdir -p /app
|
35
network_checker/Vagrantfile
vendored
35
network_checker/Vagrantfile
vendored
@ -6,39 +6,20 @@ VAGRANTFILE_API_VERSION = "2"
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
|
||||
config.vm.box = "centos"
|
||||
|
||||
config.vm.box_url = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.4-i386-v20130427.box"
|
||||
config.vm.box = "precise64"
|
||||
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.customize ["modifyvm", :id, "--memory", 348]
|
||||
end
|
||||
|
||||
config.vm.define :develop do |config|
|
||||
config.vm.network :private_network, ip: "192.168.0.2"
|
||||
config.vm.network :private_network, ip: "10.10.0.5"
|
||||
config.vm.network :private_network, ip: '10.100.0.0', type: "dhcp"
|
||||
config.vm.network :private_network, ip: '10.200.0.0', type: 'dhcp'
|
||||
config.vm.provision :shell, :inline => "echo 'deb http://fuel-repository.mirantis.com/fwm/5.0/ubuntu precise main' >> /etc/apt/sources.list"
|
||||
config.vm.provision :shell, :inline => "sudo apt-get update"
|
||||
config.vm.provision :shell, :inline => "sudo apt-get -y --force-yes install cliff-tablib python-pyparsing python-pypcap scapy python-pip vde2"
|
||||
config.vm.provision :shell, :inline => "sudo pip install pytest mock"
|
||||
config.vm.provision :shell, :inline => "cd /vagrant && sudo python setup.py develop"
|
||||
end
|
||||
|
||||
config.vm.define :dhcp2 do |config|
|
||||
config.vm.network :private_network, ip: "10.10.0.8"
|
||||
config.vm.provision :shell, :inline => "sudo yum -y install dhcp"
|
||||
config.vm.provision :shell, :inline => "sudo route add -host 255.255.255.255 dev eth1"
|
||||
config.vm.provision :shell, :inline => "sudo cp /vagrant/test_utils/dhcpd.conf.sample2 /etc/dhcp/dhcpd.conf"
|
||||
config.vm.provision :shell, :inline => "sudo /usr/sbin/dhcpd eth1"
|
||||
end
|
||||
|
||||
config.vm.define :dhcp_relay do |config|
|
||||
config.vm.network :private_network, ip: "10.10.0.10"
|
||||
config.vm.provision :shell, :inline => "sudo yum -y install dhcp"
|
||||
config.vm.provision :shell, :inline => "cp /vagrant/test_utils/dhcp_relay.conf /etc/sysconfig/dhcrelay"
|
||||
config.vm.provision :shell, :inline => "service dhcrelay start"
|
||||
end
|
||||
|
||||
config.vm.define :dhcp1 do |config|
|
||||
config.vm.network :private_network, ip: "192.168.0.5"
|
||||
config.vm.provision :shell, :inline => "sudo yum -y install dhcp"
|
||||
config.vm.provision :shell, :inline => "sudo route add -host 255.255.255.255 dev eth1"
|
||||
config.vm.provision :shell, :inline => "sudo cp /vagrant/test_utils/dhcpd.conf.sample /etc/dhcp/dhcpd.conf"
|
||||
config.vm.provision :shell, :inline => "sudo /usr/sbin/dhcpd eth1"
|
||||
end
|
||||
end
|
||||
|
44
network_checker/conftest.py
Normal file
44
network_checker/conftest.py
Normal file
@ -0,0 +1,44 @@
|
||||
# Copyright 2014 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
|
||||
|
||||
PIDFILE = '/tmp/vde_network_checker'
|
||||
IFACES = ['tap11', 'tap12']
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--vde", action='store_true', default=False,
|
||||
help="Use vde switch for network verification.")
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
if config.getoption('vde'):
|
||||
base = 'vde_switch -p {pidfile} -d'.format(pidfile=PIDFILE)
|
||||
command = [base]
|
||||
taps = ['-tap {tap}'.format(tap=tap) for tap in IFACES]
|
||||
full_command = command + taps
|
||||
os.system(' '.join(full_command))
|
||||
for tap in IFACES:
|
||||
os.system('ifconfig {tap} up'.format(tap=tap))
|
||||
os.environ['NET_CHECK_IFACE_1'] = IFACES[0]
|
||||
os.environ['NET_CHECK_IFACE_2'] = IFACES[1]
|
||||
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
if os.path.exists(PIDFILE):
|
||||
with open(PIDFILE) as f:
|
||||
pid = f.read().strip()
|
||||
os.kill(int(pid), 15)
|
@ -24,26 +24,21 @@ from dhcp_checker import utils
|
||||
|
||||
class TestDhcpServers(unittest.TestCase):
|
||||
|
||||
def test_dhcp_server_on_eth0(self):
|
||||
"""Test verifies dhcp server on eth0 iface
|
||||
"""
|
||||
response = api.check_dhcp_on_eth('eth0', 2)
|
||||
self.assertEqual(len(response), 1)
|
||||
self.assertEqual(response[0]['server_ip'], '10.0.2.2')
|
||||
|
||||
def test_dhcp_server_on_eth1(self):
|
||||
"""Test verifies dhcp server on eth1 iface
|
||||
"""
|
||||
response = api.check_dhcp_on_eth('eth1', 2)
|
||||
self.assertEqual(len(response), 1)
|
||||
self.assertEqual(response[0]['server_ip'], '192.168.0.5')
|
||||
# we need to guarantee that received answer has server_ip
|
||||
# but dont want to check its real address
|
||||
self.assertTrue(response[0]['server_ip'])
|
||||
|
||||
def test_dhcp_server_on_eth2(self):
|
||||
"""Test verifies dhcp server on eth2 iface
|
||||
"""
|
||||
response = api.check_dhcp_on_eth('eth2', 2)
|
||||
self.assertEqual(len(response), 1)
|
||||
self.assertEqual(response[0]['server_ip'], '10.10.0.8')
|
||||
self.assertTrue(response[0]['server_ip'])
|
||||
|
||||
|
||||
class TestDhcpUtils(unittest.TestCase):
|
||||
@ -83,7 +78,7 @@ class TestDhcpWithNetworkDown(unittest.TestCase):
|
||||
response = api.check_dhcp_on_eth(iface, 2)
|
||||
|
||||
self.assertEqual(len(response), 1)
|
||||
self.assertEqual(response[0]['server_ip'], '10.10.0.8')
|
||||
self.assertTrue(response[0]['server_ip'])
|
||||
self.assertEqual(manager.pre_iface_state, 'DOWN')
|
||||
self.assertEqual(manager.iface_state, 'UP')
|
||||
self.assertEqual(manager.post_iface_state, 'DOWN')
|
||||
@ -96,7 +91,7 @@ class TestDhcpWithNetworkDown(unittest.TestCase):
|
||||
response = api.check_dhcp_on_eth(iface, 2)
|
||||
|
||||
self.assertEqual(len(response), 1)
|
||||
self.assertEqual(response[0]['server_ip'], '10.0.2.2')
|
||||
self.assertTrue(response[0]['server_ip'])
|
||||
self.assertEqual(manager.pre_iface_state, 'UP')
|
||||
self.assertEqual(manager.iface_state, 'UP')
|
||||
self.assertEqual(manager.post_iface_state, 'UP')
|
||||
@ -116,15 +111,15 @@ class TestDhcpWithNetworkDown(unittest.TestCase):
|
||||
class TestMainFunctions(unittest.TestCase):
|
||||
|
||||
def test_with_vlans(self):
|
||||
config = {'eth0': (100, 101), 'eth1': (103, 105),
|
||||
config = {'eth1': (103, 105),
|
||||
'eth2': range(106, 120)}
|
||||
result = api.check_dhcp_with_vlans(config)
|
||||
self.assertEqual(len(list(result)), 3)
|
||||
self.assertEqual(len(list(result)), 2)
|
||||
|
||||
def test_with_duplicated_with_repeat(self):
|
||||
ifaces = ['eth0', 'eth1', 'eth2']
|
||||
ifaces = ['eth1', 'eth2']
|
||||
result = api.check_dhcp(ifaces, repeat=3)
|
||||
self.assertEqual(len(list(result)), 3)
|
||||
self.assertEqual(len(list(result)), 2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -29,10 +29,11 @@ from net_check import api
|
||||
class BaseListenerTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self, config=None):
|
||||
self.iface = os.environ.get('NET_CHECK_IFACE_1', 'eth1')
|
||||
default_config = {
|
||||
"src": "1.0.0.0", "ready_port": None,
|
||||
"ready_address": "localhost", "dst": "1.0.0.0",
|
||||
"interfaces": {"eth0": "0,100,100,101,102,103,104,105,106,107"},
|
||||
"interfaces": {self.iface: "0,100,101,102,103,104,105,106,107"},
|
||||
"action": "listen",
|
||||
"cookie": "Nailgun:", "dport": 31337, "sport": 31337,
|
||||
"src_mac": None, "dump_file": "/var/tmp/net-probe-dump"
|
||||
@ -72,34 +73,48 @@ class BaseListenerTestCase(unittest.TestCase):
|
||||
os.unlink(self.config['dump_file'])
|
||||
|
||||
|
||||
class TestCaseListenerPcapFile(BaseListenerTestCase):
|
||||
class TestCaseListenerPcap(BaseListenerTestCase):
|
||||
|
||||
def send_packets(self):
|
||||
directory_path = os.path.dirname(__file__)
|
||||
scapy_data = scapy.rdpcap(os.path.join(directory_path, 'vlan.pcap'))
|
||||
for p in scapy_data:
|
||||
scapy.sendp(p, iface='eth0')
|
||||
for vlan in self.config['interfaces'][self.iface].split(','):
|
||||
p = self.get_packet(vlan)
|
||||
for i in xrange(5):
|
||||
scapy.sendp(p, iface=self.iface)
|
||||
|
||||
def get_packet(self, vlan):
|
||||
normal_data = 'Nailgun:{iface} 1'.format(iface=self.iface)
|
||||
p = scapy.Ether(src='64:0b:36:0e:0a:b7',
|
||||
dst="ff:ff:ff:ff:ff:ff")
|
||||
if int(vlan) > 0:
|
||||
p = p / scapy.Dot1Q(vlan=int(vlan))
|
||||
message_len = len(normal_data) + 8
|
||||
p = p / scapy.IP(src=self.config['src'], dst=self.config['dst'])
|
||||
p = p / scapy.UDP(sport=self.config['sport'],
|
||||
dport=self.config['dport'],
|
||||
len=message_len) / normal_data
|
||||
return p
|
||||
|
||||
def test_listener_pcap_file(self):
|
||||
|
||||
with open(self.config['dump_file'], 'r') as f:
|
||||
data = json.loads(f.read())
|
||||
|
||||
self.assertEqual(data, {u'eth0': {
|
||||
u'102': {u'1': [u'eth0'], u'2': [u'eth0']},
|
||||
u'103': {u'1': [u'eth0'], u'2': [u'eth0']},
|
||||
u'100': {u'1': [u'eth0'], u'2': [u'eth0']},
|
||||
u'101': {u'1': [u'eth0'], u'2': [u'eth0']},
|
||||
u'106': {u'1': [u'eth0'], u'2': [u'eth0']},
|
||||
u'107': {u'1': [u'eth0'], u'2': [u'eth0']},
|
||||
u'104': {u'1': [u'eth0'], u'2': [u'eth0']},
|
||||
u'105': {u'1': [u'eth0'], u'2': [u'eth0']}}})
|
||||
self.assertEqual(data, {self.iface: {
|
||||
u'0': {u'1': [self.iface]},
|
||||
u'102': {u'1': [self.iface]},
|
||||
u'103': {u'1': [self.iface]},
|
||||
u'100': {u'1': [self.iface]},
|
||||
u'101': {u'1': [self.iface]},
|
||||
u'106': {u'1': [self.iface]},
|
||||
u'107': {u'1': [self.iface]},
|
||||
u'104': {u'1': [self.iface]},
|
||||
u'105': {u'1': [self.iface]}}})
|
||||
|
||||
|
||||
class TestCaseListenerCorruptedData(BaseListenerTestCase):
|
||||
|
||||
def send_packets(self):
|
||||
normal_data = 'Nailgun:eth0 2'
|
||||
normal_data = 'Nailgun:{iface} 2'.format(iface=self.iface)
|
||||
corrupted_data = normal_data + '7h 7\00\00\00'
|
||||
message_len = len(normal_data) + 8
|
||||
p = scapy.Ether(src=self.config['src_mac'],
|
||||
@ -109,26 +124,24 @@ class TestCaseListenerCorruptedData(BaseListenerTestCase):
|
||||
dport=self.config['dport'],
|
||||
len=message_len) / corrupted_data
|
||||
for i in xrange(5):
|
||||
scapy.sendp(p, iface='eth0')
|
||||
scapy.sendp(p, iface=self.iface)
|
||||
|
||||
def test_listener_corrupted_data(self):
|
||||
|
||||
with open(self.config['dump_file'], 'r') as f:
|
||||
data = json.loads(f.read())
|
||||
|
||||
self.assertEqual(data, {u'eth0': {u'0': {u'2': [u'eth0']}}})
|
||||
self.assertEqual(data, {self.iface: {u'0': {u'2': [self.iface]}}})
|
||||
|
||||
|
||||
class TestNetCheckSender(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
directory_path = os.path.dirname(__file__)
|
||||
self.scapy_data = scapy.rdpcap(os.path.join(directory_path,
|
||||
'vlan.pcap'))
|
||||
self.iface = os.environ.get('NET_CHECK_IFACE_1', 'eth1')
|
||||
self.config = {
|
||||
"src": "1.0.0.0", "ready_port": 31338,
|
||||
"ready_address": "localhost", "dst": "1.0.0.0",
|
||||
"interfaces": {"eth0": "0,100,101,102,106,107,108"},
|
||||
"interfaces": {self.iface: "0,100,101,102,106,107,108"},
|
||||
"action": "listen",
|
||||
"cookie": "Nailgun:", "dport": 31337, "sport": 31337,
|
||||
"src_mac": None,
|
||||
@ -137,8 +150,8 @@ class TestNetCheckSender(unittest.TestCase):
|
||||
}
|
||||
|
||||
def start_pcap_listener(self):
|
||||
self.pcap_listener = pcap.pcap('eth0')
|
||||
self.vlan_pcap_listener = pcap.pcap('eth0')
|
||||
self.pcap_listener = pcap.pcap(self.iface)
|
||||
self.vlan_pcap_listener = pcap.pcap(self.iface)
|
||||
filter_string = 'udp and dst port {0}'.format(self.config['dport'])
|
||||
self.vlan_pcap_listener.setfilter('vlan and {0}'.format(filter_string))
|
||||
self.pcap_listener.setfilter(filter_string)
|
||||
@ -173,5 +186,5 @@ class TestNetCheckSender(unittest.TestCase):
|
||||
time.sleep(3)
|
||||
self.sender.join()
|
||||
|
||||
expected_vlans = set(self.config['interfaces']['eth0'].split(','))
|
||||
expected_vlans = set(self.config['interfaces'][self.iface].split(','))
|
||||
self.assertEqual(expected_vlans, self.received_vlans)
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user