diff options
author | Naoto Hanaue <hanaue.naoto@po.ntts.co.jp> | 2015-09-02 17:43:39 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-09-04 22:15:12 +0900 |
commit | 03789fa0cee9a11bf272d202c74bf03f2ad0ec51 (patch) | |
tree | f6c5a5cc80b7f5df60586ea36f338c3020e170ce | |
parent | 52c96558a2fd993cd0ce380785740198ffa00c62 (diff) |
scenario_test: add zebra test
-rw-r--r-- | test/scenario_test/bgp_zebra_test.py | 175 | ||||
-rw-r--r-- | test/scenario_test/lib/base.py | 31 | ||||
-rw-r--r-- | test/scenario_test/lib/gobgp.py | 45 | ||||
-rw-r--r-- | test/scenario_test/lib/quagga.py | 29 |
4 files changed, 272 insertions, 8 deletions
diff --git a/test/scenario_test/bgp_zebra_test.py b/test/scenario_test/bgp_zebra_test.py new file mode 100644 index 00000000..e8170086 --- /dev/null +++ b/test/scenario_test/bgp_zebra_test.py @@ -0,0 +1,175 @@ +# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. +# +# 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 unittest +from fabric.api import local +from lib import base +from lib.gobgp import * +from lib.quagga import * +import sys +import os +import time +import nose +from noseplugin import OptionParser, parser_option +from itertools import chain + +class GoBGPTestBase(unittest.TestCase): + + @classmethod + def setUpClass(cls): + gobgp_ctn_image_name = parser_option.gobgp_image + base.TEST_PREFIX = parser_option.test_prefix + + g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1', + ctn_image_name=gobgp_ctn_image_name, + log_level=parser_option.gobgp_log_level, + zebra=True) + q1 = QuaggaBGPContainer(name='q1', asn=65001, router_id='192.168.0.2', zebra=True) + o1 = QuaggaBGPContainer(name='o1', asn=65002, router_id='192.168.0.3') + o2 = QuaggaBGPContainer(name='o2', asn=65002, router_id='192.168.0.4') + + # preparing the bridge of ipv4 + br01v4 = Bridge(name='br01', subnet='192.168.10.0/24') + br02v4 = Bridge(name='br02', subnet='192.168.20.0/24') + br03v4 = Bridge(name='br03', subnet='192.168.30.0/24') + + # preparing the bridge of ipv6 + br01v6 = Bridge(name='br01', subnet='2001:10::/32') + br02v6 = Bridge(name='br02', subnet='2001:20::/32') + br03v6 = Bridge(name='br03', subnet='2001:30::/32') + + cls.ctns = [g1, q1, o1, o2] + cls.gobgps = {'g1': g1} + cls.quaggas = {'q1': q1} + cls.others = {'o1': o1, 'o2': o2} + cls.bridges = {'ipv4': {'br01': br01v4, 'br02': br02v4, 'br03': br03v4}, + 'ipv6': {'br01': br01v6, 'br02': br02v6, 'br03': br03v6}} + + """ + No.1 start up ipv4 containers and check state + each neighbor is established in ipv4 environment + """ + def test_01_check_neighbor_established(self): + g1 = self.gobgps['g1'] + q1 = self.quaggas['q1'] + o1 = self.others['o1'] + o2 = self.others['o2'] + + # start up containers of ipv4 environment + initial_wait_time = max(ctn.run() for ctn in self.ctns) + time.sleep(initial_wait_time) + + # make ipv4 bridge and set ip to each container + [self.bridges['ipv4']['br01'].addif(ctn) for ctn in [o1, g1]] + [self.bridges['ipv4']['br02'].addif(ctn) for ctn in [g1, q1]] + [self.bridges['ipv4']['br03'].addif(ctn) for ctn in [q1, o2]] + + for _, q in self.quaggas.items(): + g1.add_peer(q) + q.add_peer(g1) + + g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q1) + + """ + No.2 check whether the ping is reachable in container + that have previously beyond the gobpg in ipv4 environment + """ + def test_02_check_reachablily_beyond_gobgp_from_quagga(self): + g1 = self.gobgps['g1'] + q1 = self.quaggas['q1'] + o1 = self.others['o1'] + + next_hop = g1.ip_addrs[1][1].split('/')[0] + o1.add_static_route(self.bridges['ipv4']['br01'].subnet, next_hop) + q1.get_reachablily('192.168.30.2') + + """ + No.3 check whether the ping is reachable in container + that have previously beyond the quagga in ipv4 environment + """ + def test_03_check_reachablily_beyond_quagga_from_gobgp(self): + g1 = self.gobgps['g1'] + q1 = self.quaggas['q1'] + o2 = self.others['o2'] + + next_hop = q1.ip_addrs[0][1].split('/')[0] + o2.add_static_route(self.bridges['ipv4']['br03'].subnet, next_hop) + g1.get_reachablily('192.168.10.2') + + """ + No.4 start up ipv4 containers and check state + each neighbor is established in ipv6 environment + """ + def test_04_check_neighbor_established_v6(self): + g1 = self.gobgps['g1'] + q1 = self.quaggas['q1'] + o1 = self.others['o1'] + o2 = self.others['o2'] + + # stop containers of ipv4 environment + # and start up containers of ipv6 environment + [ctn.stop() for ctn in self.ctns] + initial_wait_time = max(ctn.run() for ctn in self.ctns) + time.sleep(initial_wait_time) + + # make ipv4 bridge and set ip to each container + [self.bridges['ipv6']['br01'].addif(ctn) for ctn in [o1, g1]] + [self.bridges['ipv6']['br02'].addif(ctn) for ctn in [g1, q1]] + [self.bridges['ipv6']['br03'].addif(ctn) for ctn in [q1, o2]] + + for _, q in self.quaggas.items(): + g1.add_peer(q) + q.add_peer(g1) + + g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q1) + + """ + No.5 check whether the ping is reachable in container + that have previously beyond the gobpg in ipv6 environment + """ + def test_05_check_reachablily_beyond_gobgp_from_quagga(self): + g1 = self.gobgps['g1'] + q1 = self.quaggas['q1'] + o1 = self.others['o1'] + + next_hop = g1.ip_addrs[1][1].split('/')[0] + o1.add_static_route(self.bridges['ipv6']['br01'].subnet, next_hop) + q1.get_reachablily('2001:30::2') + + """ + No.6 check whether the ping is reachable in container + that have previously beyond the quagga in ipv6 environment + """ + def test_06_check_reachablily_beyond_quagga_from_gobgp(self): + g1 = self.gobgps['g1'] + q1 = self.quaggas['q1'] + o2 = self.others['o2'] + + next_hop = q1.ip_addrs[0][1].split('/')[0] + o2.add_static_route(self.bridges['ipv6']['br03'].subnet, next_hop) + g1.get_reachablily('2001:10::2') + + +if __name__ == '__main__': + if os.geteuid() is not 0: + print "you are not root." + sys.exit(1) + output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True) + if int(output) is not 0: + print "docker not found" + sys.exit(1) + + nose.main(argv=sys.argv, addplugins=[OptionParser()], + defaultTest=sys.argv[0]) diff --git a/test/scenario_test/lib/base.py b/test/scenario_test/lib/base.py index 7f73516b..42cdc0e1 100644 --- a/test/scenario_test/lib/base.py +++ b/test/scenario_test/lib/base.py @@ -86,6 +86,8 @@ def make_gobgp_ctn(tag='gobgp', local_gobgp_path='', from_image='golang:1.4'): c << 'RUN go install github.com/osrg/gobgp/gobgpd' c << 'RUN go get github.com/osrg/gobgp/gobgp' c << 'RUN go install github.com/osrg/gobgp/gobgp' + c << 'RUN apt-get update' + c << 'RUN apt-get install -qy --no-install-recommends quagga telnet' rindex = local_gobgp_path.rindex('gobgp') if rindex < 0: @@ -133,6 +135,7 @@ class Bridge(object): name = ctn.next_if_name() self.ctns.append(ctn) if self.with_ip: + ctn.pipework(self, self.next_ip_address(), name) else: ctn.pipework(self, '0/0', name) @@ -312,6 +315,30 @@ class BGPContainer(Container): def get_neighbor_state(self, peer_id): raise Exception('implement get_neighbor() method') + def get_reachablily(self, prefix, timeout=20): + version = netaddr.IPNetwork(prefix).version + addr = prefix.split('/')[0] + if version == 4: + ping_cmd = 'ping' + elif version == 6: + ping_cmd = 'ping6' + else: + raise Exception('unsupported route family: {0}'.format(version)) + cmd = '/bin/{0} -c 1 -w 1 {1}'.format(ping_cmd, addr) + + interval = 1 + count = 0 + while True: + res = self.local(cmd, capture=True) + print colors.yellow(res) + if '0% packet loss' in res: + break + time.sleep(interval) + count += interval + if count >= timeout: + raise Exception('timeout') + return True + def wait_for(self, expected_state, peer, timeout=120): interval = 1 count = 0 @@ -329,6 +356,10 @@ class BGPContainer(Container): if count >= timeout: raise Exception('timeout') + def add_static_route(self, network, next_hop): + cmd = '/sbin/ip route add {0} via {1}'.format(network, next_hop) + self.local(cmd) + def create_config(self): raise Exception('implement create_config() method') diff --git a/test/scenario_test/lib/gobgp.py b/test/scenario_test/lib/gobgp.py index 04b89ffe..f969ca14 100644 --- a/test/scenario_test/lib/gobgp.py +++ b/test/scenario_test/lib/gobgp.py @@ -22,23 +22,29 @@ from itertools import chain class GoBGPContainer(BGPContainer): SHARED_VOLUME = '/root/shared_volume' + QUAGGA_VOLUME = '/etc/quagga' def __init__(self, name, asn, router_id, ctn_image_name='gobgp', - log_level='debug'): + log_level='debug', zebra=False): super(GoBGPContainer, self).__init__(name, asn, router_id, ctn_image_name) self.shared_volumes.append((self.config_dir, self.SHARED_VOLUME)) + self.log_level = log_level self.prefix_set = None self.neighbor_set = None self.bgp_set = None self.default_policy = None + self.zebra = zebra def _start_gobgp(self): + zebra_op = '' + if self.zebra: + zebra_op = '-z' c = CmdBuffer() c << '#!/bin/bash' - c << '/go/bin/gobgpd -f {0}/gobgpd.conf -l {1} -p > ' \ - '{0}/gobgpd.log 2>&1'.format(self.SHARED_VOLUME, self.log_level) + c << '/go/bin/gobgpd -f {0}/gobgpd.conf -l {1} -p {2} > ' \ + '{0}/gobgpd.log 2>&1'.format(self.SHARED_VOLUME, self.log_level, zebra_op) cmd = 'echo "{0:s}" > {1}/start.sh'.format(c, self.config_dir) local(cmd, capture=True) @@ -46,8 +52,16 @@ class GoBGPContainer(BGPContainer): local(cmd, capture=True) self.local("{0}/start.sh".format(self.SHARED_VOLUME), flag='-d') + def _start_zebra(self): + cmd = 'cp {0}/zebra.conf {1}/'.format(self.SHARED_VOLUME, self.QUAGGA_VOLUME) + self.local(cmd) + cmd = '/usr/lib/quagga/zebra -f {0}/zebra.conf'.format(self.QUAGGA_VOLUME) + self.local(cmd, flag='-d') + def run(self): super(GoBGPContainer, self).run() + if self.zebra: + self._start_zebra() self._start_gobgp() return self.WAIT_FOR_BOOT @@ -152,6 +166,11 @@ class GoBGPContainer(BGPContainer): self.bgp_set = bs def create_config(self): + self._create_config_bgp() + if self.zebra: + self._create_config_zebra() + + def _create_config_bgp(self): config = {'Global': {'GlobalConfig': {'As': self.asn, 'RouterId': self.router_id}}} for peer, info in self.peers.iteritems(): afi_safi_list = [] @@ -259,9 +278,25 @@ class GoBGPContainer(BGPContainer): print colors.yellow(indent(toml.dumps(config))) f.write(toml.dumps(config)) + def _create_config_zebra(self): + c = CmdBuffer() + c << 'hostname zebra' + c << 'password zebra' + c << 'log file {0}/zebra.log'.format(self.QUAGGA_VOLUME) + + with open('{0}/zebra.conf'.format(self.config_dir), 'w') as f: + print colors.yellow('[{0}\'s new config]'.format(self.name)) + print colors.yellow(indent(str(c))) + f.writelines(str(c)) + def reload_config(self): - cmd = '/usr/bin/pkill gobgpd -SIGHUP' - self.local(cmd) + daemon = [] + daemon.append('gobgpd') + if self.zebra: + daemon.append('zebra') + for d in daemon: + cmd = '/usr/bin/pkill {0} -SIGHUP'.format(d) + self.local(cmd) for v in self.routes.itervalues(): if v['rf'] == 'ipv4' or v['rf'] == 'ipv6': cmd = 'gobgp global '\ diff --git a/test/scenario_test/lib/quagga.py b/test/scenario_test/lib/quagga.py index 8d3e0612..b881f6ed 100644 --- a/test/scenario_test/lib/quagga.py +++ b/test/scenario_test/lib/quagga.py @@ -44,10 +44,11 @@ class QuaggaBGPContainer(BGPContainer): WAIT_FOR_BOOT = 1 SHARED_VOLUME = '/etc/quagga' - def __init__(self, name, asn, router_id, ctn_image_name='osrg/quagga'): + def __init__(self, name, asn, router_id, ctn_image_name='osrg/quagga', zebra=False): super(QuaggaBGPContainer, self).__init__(name, asn, router_id, ctn_image_name) self.shared_volumes.append((self.config_dir, self.SHARED_VOLUME)) + self.zebra = zebra def run(self): super(QuaggaBGPContainer, self).run() @@ -152,6 +153,11 @@ class QuaggaBGPContainer(BGPContainer): raise Exception('not found peer {0}'.format(peer.router_id)) def create_config(self): + self._create_config_bgp() + if self.zebra: + self._create_config_zebra() + + def _create_config_bgp(self): c = CmdBuffer() c << 'hostname bgpd' c << 'password zebra' @@ -205,6 +211,23 @@ class QuaggaBGPContainer(BGPContainer): print colors.yellow(indent(str(c))) f.writelines(str(c)) + def _create_config_zebra(self): + c = CmdBuffer() + c << 'hostname zebra' + c << 'password zebra' + c << 'log file {0}/zebra.log'.format(self.SHARED_VOLUME) + + with open('{0}/zebra.conf'.format(self.config_dir), 'w') as f: + print colors.yellow('[{0}\'s new config]'.format(self.name)) + print colors.yellow(indent(str(c))) + f.writelines(str(c)) + def reload_config(self): - cmd = '/usr/bin/pkill bgpd -SIGHUP' - self.local(cmd) + daemon = [] + daemon.append('bgpd') + if self.zebra: + daemon.append('zebra') + for d in daemon: + cmd = '/usr/bin/pkill {0} -SIGHUP'.format(d) + self.local(cmd) + |