[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/INT/INT.params b/TestON/tests/USECASE/SegmentRouting/INT/INT.params
index e73c627..7f712f5 100644
--- a/TestON/tests/USECASE/SegmentRouting/INT/INT.params
+++ b/TestON/tests/USECASE/SegmentRouting/INT/INT.params
@@ -3,6 +3,7 @@
 <PARAMS>
     <testcases>1,2,3,4</testcases>
     <routerMac>00:00:0A:4C:1C:46</routerMac>
+    <use_stern>True</use_stern>
     <TREX>
         <flows>
             <RESET_QUEUE_REPORT_FILTER>
diff --git a/TestON/tests/USECASE/SegmentRouting/INT/dependencies/IntTest.py b/TestON/tests/USECASE/SegmentRouting/INT/dependencies/IntTest.py
index e10248f..2249ce2 100644
--- a/TestON/tests/USECASE/SegmentRouting/INT/dependencies/IntTest.py
+++ b/TestON/tests/USECASE/SegmentRouting/INT/dependencies/IntTest.py
@@ -3,6 +3,8 @@
 
 import os
 from tests.dependencies.Network import Network
+from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
+    Testcaselib as run
 
 class IntTest:
 
@@ -23,6 +25,7 @@
                 hostHandle.startScapy()
 
     def cleanUp(self, main):
+        run.saveOnosDiagsIfFailure(main)
         for host in self.hosts:
             if self.scapy:
                 hostHandle = getattr(main, host)
diff --git a/TestON/tests/USECASE/SegmentRouting/QOS/QOS.params b/TestON/tests/USECASE/SegmentRouting/QOS/QOS.params
index b2dd832..1861658 100644
--- a/TestON/tests/USECASE/SegmentRouting/QOS/QOS.params
+++ b/TestON/tests/USECASE/SegmentRouting/QOS/QOS.params
@@ -14,6 +14,7 @@
         <appName>onos-classic</appName>
         <namespace>tost</namespace>
     </kubernetes>
+    <use_stern>True</use_stern>
 
     <UP4>
         <s1u_address>10.32.11.126</s1u_address>
diff --git a/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.params b/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.params
index 6163c7d..6bd2069 100644
--- a/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.params
+++ b/TestON/tests/USECASE/SegmentRouting/QOSNonMobile/QOSNonMobile.params
@@ -14,6 +14,7 @@
         <appName>onos-classic</appName>
         <namespace>tost</namespace>
     </kubernetes>
+    <use_stern>True</use_stern>
 
     <SLICING>
         <slices>
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 = {
diff --git a/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.params.tucson b/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.params.tucson
index ee37414..5ed9047 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.params.tucson
+++ b/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.params.tucson
@@ -32,6 +32,7 @@
         <appName>onos-classic</appName>
         <namespace>tost</namespace>
     </kubernetes>
+    <use_stern>True</use_stern>
 
     <ENV>
         <cellName>productionCell</cellName>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.params.tucson.debug b/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.params.tucson.debug
index 96c859f..ceee8a5 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.params.tucson.debug
+++ b/TestON/tests/USECASE/SegmentRouting/SRBridging/SRBridging.params.tucson.debug
@@ -32,6 +32,7 @@
         <appName>onos-classic</appName>
         <namespace>tost</namespace>
     </kubernetes>
+    <use_stern>True</use_stern>
 
     <ENV>
         <cellName>productionCell</cellName>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDynamicConf/SRDynamicConf.params.tofino b/TestON/tests/USECASE/SegmentRouting/SRDynamicConf/SRDynamicConf.params.tofino
index 48d8d67..d373c09 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRDynamicConf/SRDynamicConf.params.tofino
+++ b/TestON/tests/USECASE/SegmentRouting/SRDynamicConf/SRDynamicConf.params.tofino
@@ -32,6 +32,7 @@
         <appName>onos-classic</appName>
         <namespace>tost</namespace>
     </kubernetes>
+    <use_stern>True</use_stern>
 
     <PERF>
         <traffic_host>Host1</traffic_host>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params.tofino b/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params.tofino
index e47a43b..4691da4 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params.tofino
+++ b/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params.tofino
@@ -32,6 +32,7 @@
         <appName>onos-classic</appName>
         <namespace>tost</namespace>
     </kubernetes>
+    <use_stern>True</use_stern>
 
 
     <ENV>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params.tucson b/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params.tucson
index fa7076a..3eeea1e 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params.tucson
+++ b/TestON/tests/USECASE/SegmentRouting/SRRouting/SRRouting.params.tucson
@@ -33,6 +33,7 @@
         <appName>onos-classic</appName>
         <namespace>tost</namespace>
     </kubernetes>
+    <use_stern>True</use_stern>
 
     <ENV>
         <cellName>productionCell</cellName>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRRouting/dependencies/SRRoutingTest.py b/TestON/tests/USECASE/SegmentRouting/SRRouting/dependencies/SRRoutingTest.py
index 5d2402f..50d3329 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRRouting/dependencies/SRRoutingTest.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRRouting/dependencies/SRRoutingTest.py
@@ -106,7 +106,6 @@
             # Run the test with physical devices
             lib.connectToPhysicalNetwork( main )
 
-        # lib.saveOnosDiagnostics( main )
         # wait some time for onos to install the rules!
         main.log.info( "Waiting %i seconds for ONOS to program the dataplane" % float( main.params[ "timers" ][ "dhcpSleep" ] ))
         time.sleep( float( main.params[ 'timers' ][ 'dhcpSleep' ] ) )
diff --git a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.params b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.params
index 0779df9..0e5bdb9 100644
--- a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.params
+++ b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.params
@@ -14,6 +14,7 @@
         <appName>onos-classic</appName>
         <namespace>tost</namespace>
     </kubernetes>
+    <use_stern>True</use_stern>
 
     <UP4>
         <pdn_host>MgmtServer</pdn_host>
diff --git a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
index da0c0a7..f60d353 100644
--- a/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
+++ b/TestON/tests/USECASE/SegmentRouting/UP4/UP4.py
@@ -66,7 +66,6 @@
         main.step("Stop scapy and p4rt client")
         up4.teardown()
 
-        run.saveOnosDiagsIfFailure(main)
         run.cleanup(main)
 
     def CASE2(self, main):
@@ -266,7 +265,6 @@
         up4.teardown()
         bess_host.stopScapy()
 
-        run.saveOnosDiagsIfFailure(main)
         run.cleanup(main)
 
     def CASE3(self, main):
@@ -395,7 +393,6 @@
                 onos_0_flow_count, onos_1_flow_count, onos_2_flow_count)
         )
 
-        run.saveOnosDiagsIfFailure(main)
         run.cleanup(main)
 
     def CASE4(self, main):
@@ -558,7 +555,6 @@
 
         run.checkFlows(main, minFlowCount=initial_flow_count)
 
-        run.saveOnosDiagsIfFailure(main)
         run.cleanup(main)
 
     def CASE5(self, main):
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
index 59466be..99327f7 100644
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
@@ -24,6 +24,7 @@
 import urllib
 import re
 import pexpect
+from distutils.util import strtobool
 from core import utilities
 
 
@@ -775,8 +776,6 @@
                     utilities.assert_equals( expect=expect, actual=pa,
                                              onpass="IP connectivity successfully tested",
                                              onfail="IP connectivity failed" )
-            if pa != expect:
-                Testcaselib.saveOnosDiagnostics( main )
             if skipOnFail and pa != expect:
                 Testcaselib.cleanup( main, copyKarafLog=False )
                 main.skipCase()
@@ -839,7 +838,6 @@
                                                  onpass="IP connectivity successfully tested",
                                                  onfail="IP connectivity failed" )
                         if pa != expect:
-                            Testcaselib.saveOnosDiagnostics( main )
                             if skipOnFail:
                                 Testcaselib.cleanup( main, copyKarafLog=False )
                                 main.skipCase()
@@ -1241,7 +1239,11 @@
             main.Network.disconnectFromNet()
 
         if copyKarafLog:
-            main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
+            useStern = strtobool( main.params.get( "use_stern", "False" ) )
+            main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=False,
+                                     includeCaseDesc=False, useStern=useStern )
+
+        Testcaselib.saveOnosDiagsIfFailure( main )
 
         if not main.persistentSetup:
             for ctrl in main.Cluster.active():
@@ -1520,7 +1522,6 @@
                                  onpass="Verify ONOS host IP succeded",
                                  onfail="Verify ONOS host IP failed" )
         if not ipResult and skipOnFail:
-            Testcaselib.saveOnosDiagnostics( main )
             Testcaselib.cleanup( main, copyKarafLog=False )
             main.skipCase()
 
@@ -1625,7 +1626,6 @@
                                  onpass="Verify traffic to {}: Pass".format( dstIp ),
                                  onfail="Verify traffic to {}: Fail".format( dstIp ) )
         if skipOnFail and result != main.TRUE:
-            Testcaselib.saveOnosDiagnostics( main )
             Testcaselib.cleanup( main, copyKarafLog=False )
             main.skipCase()
 
@@ -1682,7 +1682,6 @@
                                  onpass="Verify {} multicast traffic: Pass".format( routeName ),
                                  onfail="Verify {} multicast traffic: Fail".format( routeName ) )
         if skipOnFail and result != main.TRUE:
-            Testcaselib.saveOnosDiagnostics( main )
             Testcaselib.cleanup( main, copyKarafLog=False )
             main.skipCase()
 
@@ -1705,7 +1704,6 @@
                                  onpass="{}: Pass".format( stepMsg ),
                                  onfail="{}: Fail".format( stepMsg ) )
         if not pingResult and skipOnFail:
-            Testcaselib.saveOnosDiagnostics( main )
             Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
             main.skipCase()