[SDFAB-635] Save Onos Diagnostics if a testcase fails

  - Add to Segment Routing utility module's cleanup
    function, so most tests don't need to explicitly
    call function

Change-Id: I47c8b7ae39350631037f61e5194afc1e5a40896f
diff --git a/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/dependencies/QOSNonMobileTest.py b/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/dependencies/QOSNonMobileTest.py
index d3b724f..f599c5d 100644
--- a/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/dependencies/QOSNonMobileTest.py
+++ b/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/dependencies/QOSNonMobileTest.py
@@ -7,177 +7,177 @@
 class QOSNonMobileTest:
 
     def runTest(self, main, test_idx, n_switches):
-        run.initTest(main)
-        main.log.info(main.Cluster.numCtrls)
-        main.Cluster.setRunningNode(3)
-        run.installOnos(main, skipPackage=True, cliSleep=5)
+        try:
+            run.initTest(main)
+            main.log.info(main.Cluster.numCtrls)
+            main.Cluster.setRunningNode(3)
+            run.installOnos(main, skipPackage=True, cliSleep=5)
 
-        # Use the first available ONOS instance CLI
-        onos_rest = main.Cluster.active(0).REST
-        onos_cli = main.Cluster.active(0).CLI
+            # Use the first available ONOS instance CLI
+            onos_rest = main.Cluster.active(0).REST
+            onos_cli = main.Cluster.active(0).CLI
 
-        # Load traffic config for the current test case
-        cfgFile = "%s/tests/CASE_%d.json" % (main.configPath, test_idx)
-        with open(cfgFile) as cfg:
-            testCfg = json.load(cfg)
+            # Load traffic config for the current test case
+            cfgFile = "%s/tests/CASE_%d.json" % (main.configPath, test_idx)
+            with open(cfgFile) as cfg:
+                testCfg = json.load(cfg)
 
-        trex = Trex()
-        trex.setup(main.TRexClient)
+            trex = Trex()
+            trex.setup(main.TRexClient)
 
-        original_flows_number = onos_cli.checkFlowCount()
+            original_flows_number = onos_cli.checkFlowCount()
 
-        main.step("Add and verify Slices and Traffic Classes")
-        added_slices = True
-        new_flows = 0  # one for every new TC in SLICE and 1 for every Flow Classifier
-        for slice_name in main.params["SLICING"]["slices"]:
-            slice = main.params["SLICING"]["slices"][slice_name]
-            if "slice_id" not in slice:
-                continue
-            slice_id = int(slice["slice_id"])
-            onos_rest.addSlice(slice_id=slice_id, debug=True)
-            slices_onos = onos_rest.getSlices(debug=True)
-            # Verify the slice has been added
-            added_slices = added_slices and \
-                           {"SliceId": slice_id} in json.loads(slices_onos)
+            main.step("Add and verify Slices and Traffic Classes")
+            added_slices = True
+            new_flows = 0  # one for every new TC in SLICE and 1 for every Flow Classifier
+            for slice_name in main.params["SLICING"]["slices"]:
+                slice = main.params["SLICING"]["slices"][slice_name]
+                if "slice_id" not in slice:
+                    continue
+                slice_id = int(slice["slice_id"])
+                onos_rest.addSlice(slice_id=slice_id, debug=True)
+                slices_onos = onos_rest.getSlices(debug=True)
+                # Verify the slice has been added
+                added_slices = added_slices and \
+                               {"SliceId": slice_id} in json.loads(slices_onos)
 
-            tcs = []
-            for tc in slice.get("traffic_classes", "").split(","):
-                onos_rest.addTrafficClassToSlice(slice_id=slice_id,
-                                                 traffic_class=tc,
-                                                 debug=True)
-                tcs.append({"TrafficClass": tc})
+                tcs = []
+                for tc in slice.get("traffic_classes", "").split(","):
+                    onos_rest.addTrafficClassToSlice(slice_id=slice_id,
+                                                     traffic_class=tc,
+                                                     debug=True)
+                    tcs.append({"TrafficClass": tc})
+                    new_flows += 1
+                tcs_onos = onos_rest.getTrafficClasses(slice_id=slice_id,
+                                                       debug=True)
+                # Verify the TC has been added to the slice
+                added_slices = added_slices and \
+                               sorted(json.loads(tcs_onos)) == sorted(tcs)
+            utilities.assert_equal(
+                expect=True,
+                actual=added_slices,
+                onpass="Slices and Traffic Classes installed in slicing service",
+                onfail="Error in installing Slices and Traffic Classes in slicing service"
+            )
+
+            main.step("Add and verify slicing traffic classifier")
+            flows_in_slicing = True
+            for slicing_cfg_name in main.params["SLICING"]["traffic_classification"]:
                 new_flows += 1
-            tcs_onos = onos_rest.getTrafficClasses(slice_id=slice_id,
-                                                   debug=True)
-            # Verify the TC has been added to the slice
-            added_slices = added_slices and \
-                           sorted(json.loads(tcs_onos)) == sorted(tcs)
-        utilities.assert_equal(
-            expect=True,
-            actual=added_slices,
-            onpass="Slices and Traffic Classes installed in slicing service",
-            onfail="Error in installing Slices and Traffic Classes in slicing service"
-        )
+                slicing_config = main.params["SLICING"]["traffic_classification"][
+                    slicing_cfg_name]
 
-        main.step("Add and verify slicing traffic classifier")
-        flows_in_slicing = True
-        for slicing_cfg_name in main.params["SLICING"]["traffic_classification"]:
-            new_flows += 1
-            slicing_config = main.params["SLICING"]["traffic_classification"][
-                slicing_cfg_name]
+                traffic_selector = self.__cleanupTrafficSelector(slicing_config.get("traffic_selector", []))
+                onos_rest.addSlicingClassifierFlow(
+                    slice_id=int(slicing_config.get("slice_id", "0")),
+                    traffic_class=slicing_config.get("traffic_class",
+                                                     "BEST_EFFORT"),
+                    traffic_selector=traffic_selector,
+                    debug=True
+                )
+                # Verify classifier flows
+                onos_flows = json.loads(onos_rest.getSlicingClassifierFlow(
+                    slice_id=int(slicing_config.get("slice_id", "0")),
+                    traffic_class=slicing_config.get("traffic_class",
+                                                     "BEST_EFFORT"),
+                    debug=True
+                ))
+                flows_in_slicing = flows_in_slicing and traffic_selector in onos_flows
 
-            traffic_selector = self.__cleanupTrafficSelector(slicing_config.get("traffic_selector", []))
-            onos_rest.addSlicingClassifierFlow(
-                slice_id=int(slicing_config.get("slice_id", "0")),
-                traffic_class=slicing_config.get("traffic_class",
-                                                 "BEST_EFFORT"),
-                traffic_selector=traffic_selector,
-                debug=True
+            utilities.assert_equal(
+                expect=True,
+                actual=flows_in_slicing,
+                onpass="Traffic Classifier Flows installed in slicing service",
+                onfail="Error in installing Classifier Flows in slicing service"
             )
-            # Verify classifier flows
-            onos_flows = json.loads(onos_rest.getSlicingClassifierFlow(
-                slice_id=int(slicing_config.get("slice_id", "0")),
-                traffic_class=slicing_config.get("traffic_class",
-                                                 "BEST_EFFORT"),
-                debug=True
-            ))
-            flows_in_slicing = flows_in_slicing and traffic_selector in onos_flows
 
-        utilities.assert_equal(
-            expect=True,
-            actual=flows_in_slicing,
-            onpass="Traffic Classifier Flows installed in slicing service",
-            onfail="Error in installing Classifier Flows in slicing service"
-        )
-
-        run.checkFlows(
-            main,
-            minFlowCount=original_flows_number + (new_flows * n_switches)
-        )
-
-        main.step("Send traffic with TRex")
-        for flow in testCfg["flows"]:
-            trex.createFlow(flow)
-        results = trex.sendAndReceiveTraffic(testCfg["duration"])
-        trex.verifyCongestion(results)
-
-        trex.logPortStats()
-        for flow in testCfg["flows"]:
-            trex.logFlowStats(flow)
-
-        # Assert Flow Stats
-        for flow in testCfg["flows"]:
-            if trex.isFlowStats(flow):
-                main.step("{}: Assert RX Packets".format(flow))
-                trex.assertRxPackets(flow)
-                main.step("{}: Assert Dropped Packets".format(flow))
-                trex.assertDroppedPacket(flow)
-                main.step("{}: Assert 99.9 Percentile Latency".format(flow))
-                trex.assert99_9PercentileLatency(flow)
-
-        main.step("Remove and verify slicing traffic classifier")
-        no_flows_in_slicing = True
-        for slicing_cfg_name in main.params["SLICING"]["traffic_classification"]:
-            slicing_config = main.params["SLICING"]["traffic_classification"][
-                slicing_cfg_name]
-
-            traffic_selector = self.__cleanupTrafficSelector(slicing_config.get("traffic_selector", []))
-            onos_rest.removeSlicingClassifierFlow(
-                slice_id=int(slicing_config.get("slice_id", "0")),
-                traffic_class=slicing_config.get("traffic_class",
-                                                 "BEST_EFFORT"),
-                traffic_selector=traffic_selector,
-                debug=True
+            run.checkFlows(
+                main,
+                minFlowCount=original_flows_number + (new_flows * n_switches)
             )
-            flow = onos_rest.getSlicingClassifierFlow(
-                slice_id=int(slicing_config.get("slice_id", "0")),
-                traffic_class=slicing_config.get("traffic_class",
-                                                 "BEST_EFFORT"),
-                debug=True
+
+            main.step("Send traffic with TRex")
+            for flow in testCfg["flows"]:
+                trex.createFlow(flow)
+            results = trex.sendAndReceiveTraffic(testCfg["duration"])
+            trex.verifyCongestion(results)
+
+            trex.logPortStats()
+            for flow in testCfg["flows"]:
+                trex.logFlowStats(flow)
+
+            # Assert Flow Stats
+            for flow in testCfg["flows"]:
+                if trex.isFlowStats(flow):
+                    main.step("{}: Assert RX Packets".format(flow))
+                    trex.assertRxPackets(flow)
+                    main.step("{}: Assert Dropped Packets".format(flow))
+                    trex.assertDroppedPacket(flow)
+                    main.step("{}: Assert 99.9 Percentile Latency".format(flow))
+                    trex.assert99_9PercentileLatency(flow)
+
+            main.step("Remove and verify slicing traffic classifier")
+            no_flows_in_slicing = True
+            for slicing_cfg_name in main.params["SLICING"]["traffic_classification"]:
+                slicing_config = main.params["SLICING"]["traffic_classification"][
+                    slicing_cfg_name]
+
+                traffic_selector = self.__cleanupTrafficSelector(slicing_config.get("traffic_selector", []))
+                onos_rest.removeSlicingClassifierFlow(
+                    slice_id=int(slicing_config.get("slice_id", "0")),
+                    traffic_class=slicing_config.get("traffic_class",
+                                                     "BEST_EFFORT"),
+                    traffic_selector=traffic_selector,
+                    debug=True
+                )
+                flow = onos_rest.getSlicingClassifierFlow(
+                    slice_id=int(slicing_config.get("slice_id", "0")),
+                    traffic_class=slicing_config.get("traffic_class",
+                                                     "BEST_EFFORT"),
+                    debug=True
+                )
+                no_flows_in_slicing = no_flows_in_slicing and flow == "[]"
+
+            utilities.assert_equal(
+                expect=True,
+                actual=no_flows_in_slicing,
+                onpass="Traffic Classifier Flows removed in slicing service",
+                onfail="Error in removing Classifier Flows in slicing service"
             )
-            no_flows_in_slicing = no_flows_in_slicing and flow == "[]"
 
-        utilities.assert_equal(
-            expect=True,
-            actual=no_flows_in_slicing,
-            onpass="Traffic Classifier Flows removed in slicing service",
-            onfail="Error in removing Classifier Flows in slicing service"
-        )
+            main.step("Remove and verify Slices and Traffic Classes")
+            removed_slices = []
+            for slice_name in main.params["SLICING"]["slices"]:
+                slice = main.params["SLICING"]["slices"][slice_name]
+                if "slice_id" not in slice:
+                    continue
+                slice_id = int(slice["slice_id"])
+                for tc in slice.get("traffic_classes", "").split(","):
+                    # BEST_EFFORT must be removed as last, or we can leave it,
+                    # it will be removed when removing the slice
+                    if tc != "BEST_EFFORT":
+                        onos_rest.removeTrafficClassToSlice(slice_id=slice_id,
+                                                            traffic_class=tc,
+                                                            debug=True)
+                # Do not try to remove the Default Slice!
+                if slice_id != 0:
+                    onos_rest.removeSlice(slice_id=slice_id, debug=True)
+                    removed_slices.append(slice_id)
 
-        main.step("Remove and verify Slices and Traffic Classes")
-        removed_slices = []
-        for slice_name in main.params["SLICING"]["slices"]:
-            slice = main.params["SLICING"]["slices"][slice_name]
-            if "slice_id" not in slice:
-                continue
-            slice_id = int(slice["slice_id"])
-            for tc in slice.get("traffic_classes", "").split(","):
-                # BEST_EFFORT must be removed as last, or we can leave it,
-                # it will be removed when removing the slice
-                if tc != "BEST_EFFORT":
-                    onos_rest.removeTrafficClassToSlice(slice_id=slice_id,
-                                                        traffic_class=tc,
-                                                        debug=True)
-            # Do not try to remove the Default Slice!
-            if slice_id != 0:
-                onos_rest.removeSlice(slice_id=slice_id, debug=True)
-                removed_slices.append(slice_id)
+            slices_onos = json.loads(onos_rest.getSlices(debug=True))
+            utilities.assert_equal(
+                expect=True,
+                actual=not any([{"SliceId": slice_id} in slices_onos for slice_id in
+                                removed_slices]),
+                onpass="Slices and Traffic Classes removed from slicing service",
+                onfail="Error in removing Slices and Traffic Classes from slicing service"
+            )
 
-        slices_onos = json.loads(onos_rest.getSlices(debug=True))
-        utilities.assert_equal(
-            expect=True,
-            actual=not any([{"SliceId": slice_id} in slices_onos for slice_id in
-                            removed_slices]),
-            onpass="Slices and Traffic Classes removed from slicing service",
-            onfail="Error in removing Slices and Traffic Classes from slicing service"
-        )
-
-        run.checkFlows(main, minFlowCount=original_flows_number)
-
-        main.step("Teardown")
-        trex.teardown()
-        run.saveOnosDiagsIfFailure(main)
-        run.cleanup(main)
+            run.checkFlows(main, minFlowCount=original_flows_number)
+        finally:
+            main.step("Teardown")
+            trex.teardown()
+            run.cleanup(main)
 
     def __cleanupTrafficSelector(self, traffic_selector):
         ts = {