Implement changes to cord-tester framework for vrouter configuration.
And add vrouter tests to verify routes.
diff --git a/src/test/setup/cord-test.py b/src/test/setup/cord-test.py
index 09c04db..8ac86fc 100755
--- a/src/test/setup/cord-test.py
+++ b/src/test/setup/cord-test.py
@@ -1,222 +1,16 @@
 #!/usr/bin/env python
 from argparse import ArgumentParser
 import os,sys,time
-import io
-import yaml
-from pyroute2 import IPRoute
-from itertools import chain
-from nsenter import Namespace
-from docker import Client
-from shutil import copy
 utils_dir = os.path.join( os.path.dirname(os.path.realpath(sys.argv[0])), '../utils')
 sys.path.append(utils_dir)
 from OnosCtrl import OnosCtrl
 from OltConfig import OltConfig
+from CordContainer import *
+from CordTestServer import cord_test_server_start, cord_test_server_stop
 
-class docker_netns(object):
-
-    dckr = Client()
-    def __init__(self, name):
-        pid = int(self.dckr.inspect_container(name)['State']['Pid'])
-        if pid == 0:
-            raise Exception('no container named {0}'.format(name))
-        self.pid = pid
-
-    def __enter__(self):
-        pid = self.pid
-        if not os.path.exists('/var/run/netns'):
-            os.mkdir('/var/run/netns')
-        os.symlink('/proc/{0}/ns/net'.format(pid), '/var/run/netns/{0}'.format(pid))
-        return str(pid)
-
-    def __exit__(self, type, value, traceback):
-        pid = self.pid
-        os.unlink('/var/run/netns/{0}'.format(pid))
-
-flatten = lambda l: chain.from_iterable(l)
-
-class Container(object):
-    dckr = Client()
-    def __init__(self, name, image, tag = 'latest', command = 'bash', quagga_config = None):
-        self.name = name
-        self.image = image
-        self.tag = tag
-        self.image_name = image + ':' + tag
-        self.id = None
-        self.command = command
-        if quagga_config is not None:
-            self.bridge = quagga_config['bridge']
-            self.ipaddress = quagga_config['ip']
-            self.mask = quagga_config['mask']
-        else:
-            self.bridge = None
-            self.ipaddress = None
-            self.mask = None
-
-    @classmethod
-    def build_image(cls, dockerfile, tag, force=True, nocache=False):
-        f = io.BytesIO(dockerfile.encode('utf-8'))
-        if force or not cls.image_exists(tag):
-            print('Build {0}...'.format(tag))
-            for line in cls.dckr.build(fileobj=f, rm=True, tag=tag, decode=True, nocache=nocache):
-                if 'stream' in line:
-                    print(line['stream'].strip())
-
-    @classmethod
-    def image_exists(cls, name):
-        return name in [ctn['RepoTags'][0] for ctn in cls.dckr.images()]
-
-    @classmethod
-    def create_host_config(cls, port_list = None, host_guest_map = None, privileged = False):
-        port_bindings = None
-        binds = None
-        if port_list:
-            port_bindings = {}
-            for p in port_list:
-                port_bindings[str(p)] = str(p)
-
-        if host_guest_map:
-            binds = []
-            for h, g in host_guest_map:
-                binds.append('{0}:{1}'.format(h, g))
-
-        return cls.dckr.create_host_config(binds = binds, port_bindings = port_bindings, privileged = privileged)
-
-    @classmethod
-    def cleanup(cls, image):
-        cnt_list = filter(lambda c: c['Image'] == image, cls.dckr.containers())
-        for cnt in cnt_list:
-            print('Cleaning container %s' %cnt['Id'])
-            cls.dckr.kill(cnt['Id'])
-            cls.dckr.remove_container(cnt['Id'], force=True)
-
-    @classmethod
-    def remove_container(cls, name, force=True):
-        try:
-            cls.dckr.remove_container(name, force = force)
-        except: pass
-
-    def exists(self):
-        return '/{0}'.format(self.name) in list(flatten(n['Names'] for n in self.dckr.containers()))
-
-    def img_exists(self):
-        return self.image_name in [ctn['RepoTags'][0] for ctn in self.dckr.images()]
-
-    def ip(self):
-        cnt_list = filter(lambda c: c['Image'] == self.image_name, self.dckr.containers())
-        cnt_settings = cnt_list.pop()
-        return cnt_settings['NetworkSettings']['Networks']['bridge']['IPAddress']
-
-    def kill(self, remove = True):
-        self.dckr.kill(self.name)
-        self.dckr.remove_container(self.name, force=True)
-
-    def start(self, rm = True, ports = None, volumes = None, host_config = None, 
-              environment = None, tty = False, stdin_open = True):
-
-        if rm and self.exists():
-            print('Removing container:', self.name)
-            self.dckr.remove_container(self.name, force=True)
-
-        ctn = self.dckr.create_container(image=self.image_name, ports = ports, command=self.command, 
-                                         detach=True, name=self.name,
-                                         environment = environment, 
-                                         volumes = volumes, 
-                                         host_config = host_config, stdin_open=stdin_open, tty = tty)
-        self.dckr.start(container=self.name)
-        if self.bridge:
-            self.connect_to_br()
-        self.id = ctn['Id']
-        return ctn
-
-    def connect_to_br(self):
-        with docker_netns(self.name) as pid:
-            ip = IPRoute()
-            br = ip.link_lookup(ifname=self.bridge)
-            if len(br) == 0:
-                ip.link_create(ifname=self.bridge, kind='bridge')
-                br = ip.link_lookup(ifname=self.bridge)
-            br = br[0]
-            ip.link('set', index=br, state='up')
-
-            ifs = ip.link_lookup(ifname=self.name)
-            if len(ifs) > 0:
-               ip.link_remove(ifs[0])
-
-            ip.link_create(ifname=self.name, kind='veth', peer=pid)
-            host = ip.link_lookup(ifname=self.name)[0]
-            ip.link('set', index=host, master=br)
-            ip.link('set', index=host, state='up')
-            guest = ip.link_lookup(ifname=pid)[0]
-            ip.link('set', index=guest, net_ns_fd=pid)
-            with Namespace(pid, 'net'):
-                ip = IPRoute()
-                ip.link('set', index=guest, ifname='eth1')
-                ip.addr('add', index=guest, address=self.ipaddress, mask=self.mask)
-                ip.link('set', index=guest, state='up')
-
-    def execute(self, cmd, tty = True, stream = False, shell = False):
-        res = 0
-        if type(cmd) == str:
-            cmds = (cmd,)
-        else:
-            cmds = cmd
-        if shell:
-            for c in cmds:
-                res += os.system('docker exec {0} {1}'.format(self.name, c))
-            return res
-        for c in cmds:
-            i = self.dckr.exec_create(container=self.name, cmd=c, tty = tty, privileged = True)
-            self.dckr.exec_start(i['Id'], stream = stream, detach=True)
-            result = self.dckr.exec_inspect(i['Id'])
-            res += 0 if result['ExitCode'] == None else result['ExitCode']
-        return res
-
-class Onos(Container):
-
-    quagga_config = { 'bridge' : 'quagga-br', 'ip': '10.10.0.4', 'mask' : 16 }
-    env = { 'ONOS_APPS' : 'drivers,openflow,proxyarp,aaa,igmp,vrouter' }
-    ports = [ 8181, 8101, 9876, 6653, 6633, 2000, 2620 ]
-
-    def __init__(self, name = 'cord-onos', image = 'onosproject/onos', tag = 'latest', boot_delay = 60):
-        super(Onos, self).__init__(name, image, tag = tag, quagga_config = self.quagga_config)
-        if not self.exists():
-            self.remove_container(name, force=True)
-            host_config = self.create_host_config(port_list = self.ports)
-            print('Starting ONOS container %s' %self.name)
-            self.start(ports = self.ports, environment = self.env, 
-                       host_config = host_config, tty = True)
-            print('Waiting %d seconds for ONOS to boot' %(boot_delay))
-            time.sleep(boot_delay)
-
-class Radius(Container):
-    ports = [ 1812, 1813 ]
-    env = {'TIMEZONE':'America/Los_Angeles', 
-           'DEBUG': 'true', 'cert_password':'whatever', 'primary_shared_secret':'radius_password'
-           }
-    host_db_dir = os.path.join(os.getenv('HOME'), 'services', 'radius', 'data', 'db')
-    guest_db_dir = os.path.join(os.path.sep, 'opt', 'db')
-    host_config_dir = os.path.join(os.getenv('HOME'), 'services', 'radius', 'freeradius')
-    guest_config_dir = os.path.join(os.path.sep, 'etc', 'freeradius')
-    start_command = '/root/start-radius.py'
-    host_guest_map = ( (host_db_dir, guest_db_dir),
-                       (host_config_dir, guest_config_dir)
-                       )
-    def __init__(self, name = 'cord-radius', image = 'freeradius', tag = 'podd'):
-        super(Radius, self).__init__(name, image, tag = tag, command = self.start_command)
-        if not self.exists():
-            self.remove_container(name, force=True)
-            host_config = self.create_host_config(port_list = self.ports,
-                                                  host_guest_map = self.host_guest_map)
-            volumes = []
-            for _,g in self.host_guest_map:
-                volumes.append(g)
-            self.start(ports = self.ports, environment = self.env, 
-                       volumes = volumes, 
-                       host_config = host_config, tty = True)
+test_server = cord_test_server_start()
 
 class CordTester(Container):
-
     sandbox = '/root/test'
     sandbox_setup = '/root/test/src/test/setup'
     tester_base = os.path.dirname(os.path.realpath(sys.argv[0]))
@@ -356,6 +150,7 @@
 RUN pip install -U nsenter
 RUN pip install -U pyroute2
 RUN pip install -U netaddr
+RUN apt-get -y install arping
 RUN mv /usr/sbin/tcpdump /sbin/
 RUN ln -sf /sbin/tcpdump /usr/sbin/tcpdump
 CMD ["/bin/bash"]
@@ -385,7 +180,6 @@
             self.kill(remove=True)
 
 class Quagga(Container):
-
     quagga_config = { 'bridge' : 'quagga-br', 'ip': '10.10.0.3', 'mask' : 16 }
     ports = [ 179, 2601, 2602, 2603, 2604, 2605, 2606 ]
     host_quagga_config = os.path.join(CordTester.tester_base, 'quagga-config')
@@ -439,6 +233,7 @@
 onos_app_file = os.path.abspath('{0}/../apps/ciena-cordigmp-'.format(cord_tester_base) + onos_app_version + '.oar')
 
 def runTest(args):
+    global test_server
     onos_cnt = {'tag':'latest'}
     radius_cnt = {'tag':'latest'}
     nose_cnt = {'image': 'cord-test/nose','tag': 'latest'}
@@ -507,6 +302,7 @@
     test_cnt.setup_intfs()
     tests = args.test_type.split('-')
     test_cnt.run_tests(tests)
+    cord_test_server_stop(test_server)
 
 if __name__ == '__main__':
     parser = ArgumentParser(description='Cord Tester for ONOS')
diff --git a/src/test/setup/quagga-config/start.sh b/src/test/setup/quagga-config/start.sh
index 5b140ca..77e342b 100755
--- a/src/test/setup/quagga-config/start.sh
+++ b/src/test/setup/quagga-config/start.sh
@@ -2,4 +2,5 @@
 ulimit -n 65536
 ip a add 10.10.0.3/16 dev eth1
 #bgpd -u root -f /root/config/bgpd.conf &
-/usr/local/sbin/zebra -u root -f /root/config/testrib.conf
+conf_file=${1:-/root/config/testrib.conf}
+/usr/local/sbin/zebra -u root -f $conf_file
diff --git a/src/test/setup/quagga-config/testrib.conf b/src/test/setup/quagga-config/testrib.conf
index 2a02337..af2f213 100644
--- a/src/test/setup/quagga-config/testrib.conf
+++ b/src/test/setup/quagga-config/testrib.conf
@@ -15,37 +15,6 @@
 
 ! statics that should be subsumed by connected routes, according to interface
 ! state
-ip route 50.10.0.0/24 172.17.0.4
-ip route 50.10.0.0/24 172.17.0.3
-ip route 50.10.0.0/24 172.17.0.2
-ip route 60.10.0.0/24 172.17.0.4
-ip route 60.10.0.0/24 172.17.0.3
-ip route 70.10.0.0/24 172.17.0.4
-ip route 70.10.0.0/24 172.17.0.3
-ip route 80.10.0.0/24 172.17.0.4
-ip route 80.10.0.0/24 172.17.0.3
-ip route 90.10.0.0/24 172.17.0.4
-ip route 90.10.0.0/24 172.17.0.3
-ip route 100.10.0.0/24 172.17.0.4
-ip route 100.10.0.0/24 172.17.0.3
-ip route 120.10.0.0/24 172.17.0.4
-ip route 120.10.0.0/24 172.17.0.3
-ip route 50.10.0.0/24 172.17.0.6
-ip route 50.10.0.0/24 172.17.0.3
-ip route 50.10.0.0/24 172.17.0.2
-ip route 50.10.0.0/24 172.17.0.4
-ip route 60.10.0.0/24 172.17.0.7
-ip route 60.10.0.0/24 172.17.0.3
-ip route 60.10.0.0/24 172.17.0.4
-ip route 70.10.0.0/24 172.17.0.1
-ip route 70.10.0.0/24 172.17.0.3
-ip route 70.10.0.0/24 172.17.0.2
-ip route 80.10.0.0/24 172.17.0.2
-ip route 80.10.0.0/24 172.17.0.3
-ip route 80.10.0.0/24 172.17.0.4
-ip route 90.10.0.0/24 172.17.0.3
-ip route 90.10.0.0/24 172.17.0.2
-ip route 90.10.0.0/24 172.17.0.4
 line vty
  exec-timeout 0 0
 !