Test: Implement setup --cord mode for cord-tester.
This would make the cord-tester listen for ONOS restart requests on the cord.
The restart is implemented using docker-compose when running the test agent on the ONOS compute node.
This is required because the tests restart ONOS with different configurations and the cord-tester agent
restarts bind the config volume to the xos/onos container before restarting ONOS.
Also implement fetching the device id properly when running tester under OLT configuration.
One can also override with OLT_DEVICE_ID env in the test container when multiple devices are connected to ONOS.
This is used by the subscriber test to override the pmc-olt driver for the device id when running
single-channel N subscriber tests.
Change-Id: I1fa27dd21ccacec35f38030443ad298b59718f4b
diff --git a/src/test/setup/cord-test.py b/src/test/setup/cord-test.py
index 5dabe1c..ac81fa7 100755
--- a/src/test/setup/cord-test.py
+++ b/src/test/setup/cord-test.py
@@ -363,6 +363,15 @@
onos_ip = None
radius_ip = None
+ onos_cord_loc = args.onos_cord
+ if onos_cord_loc:
+ if onos_cord_loc.find(os.path.sep) < 0:
+ onos_cord_loc = os.path.join(os.getenv('HOME'), onos_cord_loc)
+ if not os.access(onos_cord_loc, os.F_OK):
+ print('ONOS cord config location %s is not accessible' %onos_cord_loc)
+ sys.exit(1)
+ #Disable test container provisioning on the ONOS compute node
+ args.dont_provision = True
##If onos/radius was already started
if args.test_controller:
@@ -373,6 +382,14 @@
else:
radius_ip = None
+ onos_cord = None
+ if onos_cord_loc:
+ if not args.test_controller:
+ ##Unexpected case. Specify the external controller ip when running on cord node
+ print('Specify ONOS ip using \"-e\" option when running the cord-tester on cord node')
+ sys.exit(1)
+ onos_cord = OnosCord(onos_cord_loc)
+
#don't spawn onos if the user had started it externally
onos_cnt['image'] = args.onos.split(':')[0]
if args.onos.find(':') >= 0:
@@ -385,7 +402,6 @@
print('Onos IP %s' %onos_ip)
print('Installing ONOS cord apps')
Onos.install_cord_apps(onos_ip = onos_ip)
-
print('Installing cord tester ONOS app %s' %onos_app_file)
OnosCtrl.install_app(args.app, onos_ip = onos_ip)
@@ -435,7 +451,8 @@
print('Test container %s started and provisioned to run tests using nosetests' %(test_cnt.name))
#Finally start the test server and daemonize
- cord_test_server_start(daemonize = True, cord_test_host = ip, cord_test_port = port)
+ cord_test_server_start(daemonize = True, cord_test_host = ip, cord_test_port = port,
+ onos_cord = onos_cord)
def cleanupTests(args):
test_container = '{}:latest'.format(CordTester.IMAGE)
@@ -499,6 +516,8 @@
parser_setup.add_argument('-d', '--dont-provision', action='store_true', help='Dont start test container.')
parser_setup.add_argument('-p', '--olt', action='store_true', help='Use OLT config')
parser_setup.add_argument('-s', '--start-switch', action='store_true', help='Start OVS when running under OLT config')
+ parser_setup.add_argument('-c', '--onos-cord', default='', type=str,
+ help='Specify cord location for ONOS cord when running on podd')
parser_setup.set_defaults(func=setupCordTester)
parser_list = subparser.add_parser('list', help='List test cases')
diff --git a/src/test/subscriberMultiTable/subscriberMultiTableTest.py b/src/test/subscriberMultiTable/subscriberMultiTableTest.py
index a6eec2a..75c9392 100644
--- a/src/test/subscriberMultiTable/subscriberMultiTableTest.py
+++ b/src/test/subscriberMultiTable/subscriberMultiTableTest.py
@@ -179,15 +179,6 @@
olt_conf_file = os.path.join(test_path, '..', 'setup/olt_config_multitable.json')
cpqd_path = os.path.join(test_path, '..', 'setup')
ovs_path = cpqd_path
- device_id = 'of:' + get_mac('ovsbr0')
- device_dict = { "devices" : {
- "{}".format(device_id) : {
- "basic" : {
- "driver" : "pmc-olt"
- }
- }
- },
- }
test_services = ('IGMP', 'TRAFFIC')
num_joins = 0
num_subscribers = 0
@@ -195,10 +186,39 @@
recv_timeout = False
@classmethod
+ def load_device_id(cls):
+ '''If running under olt, we get the first switch connected to onos'''
+ olt = os.getenv('OLT_CONFIG', None)
+ if olt:
+ devices = OnosCtrl.get_devices()
+ if devices:
+ dids = map(lambda d: d['id'], devices)
+ if len(dids) == 1:
+ did = dids[0]
+ else:
+ ###If we have more than 1, then check for env before using first one
+ did = os.getenv('OLT_DEVICE_ID', dids[0])
+ else:
+ did = 'of:' + get_mac('ovsbr0')
+
+ #Set the default config
+ cls.device_id = did
+ cls.device_dict = { "devices" : {
+ "{}".format(did) : {
+ "basic" : {
+ "driver" : "pmc-olt"
+ }
+ }
+ },
+ }
+ return did
+
+ @classmethod
def setUpClass(cls):
'''Load the OLT config and activate relevant apps'''
+ did = cls.load_device_id()
network_cfg = { "devices" : {
- "{}".format(cls.device_id) : {
+ "{}".format(did) : {
"basic" : {
"driver" : "pmc-olt"
}
diff --git a/src/test/utils/CordContainer.py b/src/test/utils/CordContainer.py
index e5f7526..da99655 100644
--- a/src/test/utils/CordContainer.py
+++ b/src/test/utils/CordContainer.py
@@ -16,6 +16,7 @@
import os,time
import io
import json
+import yaml
from pyroute2 import IPRoute
from itertools import chain
from nsenter import Namespace
@@ -51,7 +52,10 @@
self.name = name
self.image = image
self.tag = tag
- self.image_name = image + ':' + tag
+ if tag:
+ self.image_name = image + ':' + tag
+ else:
+ self.image_name = image
self.id = None
self.command = command
self.quagga_config = quagga_config
@@ -191,6 +195,68 @@
mem = min(mem, 16)
return str(mem) + 'G'
+class OnosCord(Container):
+ """Use this when running the cord tester agent on the onos compute node"""
+ onos_cord_dir = os.path.join(os.getenv('HOME'), 'cord-tester-cord')
+ onos_config_dir_guest = '/root/onos/config'
+ onos_config_dir = os.path.join(onos_cord_dir, 'config')
+ docker_yaml = os.path.join(onos_cord_dir, 'docker-compose.yml')
+
+ def __init__(self, conf):
+ self.cord_conf_dir = conf
+ if os.access(self.cord_conf_dir, os.F_OK) and not os.access(self.onos_cord_dir, os.F_OK):
+ os.mkdir(self.onos_cord_dir)
+ os.mkdir(self.onos_config_dir)
+ ##copy the config file from cord-tester-config
+ cmd = 'cp {}/* {}'.format(self.cord_conf_dir, self.onos_cord_dir)
+ os.system(cmd)
+
+ ##update the docker yaml with the config volume
+ with open(self.docker_yaml, 'r') as f:
+ yaml_config = yaml.load(f)
+ image = yaml_config['services'].keys()[0]
+ name = 'cordtestercord_{}_1'.format(image)
+ volumes = yaml_config['services'][image]['volumes']
+ config_volumes = filter(lambda e: e.find(self.onos_config_dir_guest) >= 0, volumes)
+ if not config_volumes:
+ config_volume = '{}:{}'.format(self.onos_config_dir, self.onos_config_dir_guest)
+ volumes.append(config_volume)
+ docker_yaml_changed = '{}-changed'.format(self.docker_yaml)
+ with open(docker_yaml_changed, 'w') as wf:
+ yaml.dump(yaml_config, wf)
+
+ os.rename(docker_yaml_changed, self.docker_yaml)
+ self.volumes = volumes
+
+ super(OnosCord, self).__init__(name, image, tag = '')
+ cord_conf_dir_basename = os.path.basename(self.cord_conf_dir.replace('-', ''))
+ self.xos_onos_name = '{}_{}_1'.format(cord_conf_dir_basename, image)
+ ##Create an container instance of xos onos
+ self.xos_onos = Container(self.xos_onos_name, image, tag = '')
+
+ def start(self, restart = False, network_cfg = None):
+ if restart is True:
+ if self.exists():
+ ##Kill the existing instance
+ print('Killing container %s' %self.name)
+ self.kill()
+ if self.xos_onos.exists():
+ print('Killing container %s' %self.xos_onos.name)
+ self.xos_onos.kill()
+
+ if network_cfg is not None:
+ json_data = json.dumps(network_cfg, indent=4)
+ with open('{}/network-cfg.json'.format(self.onos_config_dir), 'w') as f:
+ f.write(json_data)
+
+ #start the container using docker-compose
+ cmd = 'cd {} && docker-compose up -d'.format(self.onos_cord_dir)
+ os.system(cmd)
+
+ def build_image(self):
+ build_cmd = 'cd {} && docker-compose build'.format(self.onos_cord_dir)
+ os.system(build_cmd)
+
class Onos(Container):
quagga_config = ( { 'bridge' : 'quagga-br', 'ip': '10.10.0.4', 'mask' : 16 }, )
@@ -240,6 +306,8 @@
print('Waiting %d seconds for ONOS to boot' %(boot_delay))
time.sleep(boot_delay)
+ self.install_cord_apps()
+
@classmethod
def install_cord_apps(cls, onos_ip = None):
for app, version in cls.onos_cord_apps:
diff --git a/src/test/utils/CordTestServer.py b/src/test/utils/CordTestServer.py
index e263939..a77b977 100644
--- a/src/test/utils/CordTestServer.py
+++ b/src/test/utils/CordTestServer.py
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-from CordContainer import Container, Onos, Quagga, Radius, reinitContainerClients
+from CordContainer import Container, Onos, OnosCord, Quagga, Radius, reinitContainerClients
from nose.tools import nottest
from SimpleXMLRPCServer import SimpleXMLRPCServer
import daemon
@@ -28,6 +28,7 @@
CORD_TEST_HOST = '172.17.0.1'
CORD_TEST_PORT = 25000
+g_onos_cord = None
class QuaggaStopWrapper(Container):
def __init__(self, name = Quagga.NAME, image = Quagga.IMAGE, tag = 'latest'):
@@ -38,14 +39,20 @@
class CordTestServer(object):
def __restart_onos(self, config = None):
- onos_config = '{}/network-cfg.json'.format(Onos.host_config_dir)
+ if g_onos_cord:
+ onos_config = '{}/network-cfg.json'.format(OnosCord.onos_config_dir)
+ else:
+ onos_config = '{}/network-cfg.json'.format(Onos.host_config_dir)
if config is None:
try:
os.unlink(onos_config)
except:
pass
print('Restarting ONOS')
- Onos(restart = True, network_cfg = config)
+ if g_onos_cord:
+ g_onos_cord.start(restart = True, network_cfg = config)
+ else:
+ Onos(restart = True, network_cfg = config)
return 'DONE'
def restart_onos(self, kwargs):
@@ -90,9 +97,12 @@
return 'DONE'
@nottest
-def cord_test_server_start(daemonize = True, cord_test_host = CORD_TEST_HOST, cord_test_port = CORD_TEST_PORT):
+def cord_test_server_start(daemonize = True, cord_test_host = CORD_TEST_HOST,
+ cord_test_port = CORD_TEST_PORT, onos_cord = None):
+ global g_onos_cord
server = SimpleXMLRPCServer( (cord_test_host, cord_test_port) )
server.register_instance(CordTestServer())
+ g_onos_cord = onos_cord
if daemonize is True:
d = daemon.DaemonContext(files_preserve = [server],
detach_process = True)