[SDFAB-1024] Modify TestON to verify persistence mastership

Additionally, improve ONOS cli driver

Change-Id: I92a6908fc5e76cdc6538dccf5845ee5a6e99662a
diff --git a/TestON/tests/USECASE/SegmentRouting/PMastership/PMastership.py b/TestON/tests/USECASE/SegmentRouting/PMastership/PMastership.py
new file mode 100644
index 0000000..886806e
--- /dev/null
+++ b/TestON/tests/USECASE/SegmentRouting/PMastership/PMastership.py
@@ -0,0 +1,287 @@
+class PMastership:
+
+    def __init__(self):
+        self.default = ''
+
+    def CASE1(self, main):
+        main.case("PMastership Test")
+        """
+        Verify there are no pending flows and groups
+        Get flows and group counts
+        Verify that are not 0
+        Get the master of leaf2 (look at the params file for the config)
+        Verify that has the master
+        Kill switch leaf2
+        Set label on switch K8S node to prevent K8S to redeploy stratum
+        Verify there are no pending flows and groups related to segment routing
+        Verify that the master of leaf2 is still the same as before
+        Wait for the switch to be up again
+        Verify there are no pending flows and groups
+        """
+        try:
+            from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
+                Testcaselib as run
+            from tests.USECASE.SegmentRouting.SRStaging.dependencies.SRStagingTest import \
+                SRStagingTest
+            import time
+        except ImportError as e:
+            main.log.error("Import not found. Exiting the test")
+            main.log.error(e)
+            main.cleanAndExit()
+        # Retrieves the params of the test
+        n_switches = int(main.params["TOPO"]["switchNum"])
+        switch_to_kill = main.params["PMastership"]["PMastership_dataplane_fail"]["switch_to_kill"]
+        k8s_switch_node = main.params["PMastership"]["PMastership_dataplane_fail"]["k8s_switch_node"]
+        k8s_label = main.params["PMastership"]["PMastership_dataplane_fail"]["k8s_label"]
+        k8s_label_value_test = main.params["PMastership"]["PMastership_dataplane_fail"]["k8s_label_value_test"]
+        k8s_label_value_normal = main.params["PMastership"]["PMastership_dataplane_fail"]["k8s_label_value_normal"]
+        # Init the main components and variables
+        run.initTest(main)
+        main.log.info(main.Cluster.numCtrls)
+        main.Cluster.setRunningNode(3)
+        run.installOnos(main, skipPackage=True, cliSleep=5)
+        onos_cli = main.Cluster.active(0).CLI
+        kubectl = main.Cluster.active(0).Bench
+        kubeconfig = main.Cluster.active(0).k8s.kubeConfig
+        namespace = main.params['kubernetes']['namespace']
+
+        main.step("Verify there are added flows")
+        initial_flows_count = onos_cli.checkFlowCount()
+        empty = main.TRUE if ( initial_flows_count == 0 ) else main.FALSE
+        utilities.assert_equal(
+            expect=main.FALSE,
+            actual=empty,
+            onpass="There are " + str(initial_flows_count) + " added flows",
+            onfail="There are no added flows",
+        )
+
+        main.step("Verify there are added groups")
+        initial_groups_count = onos_cli.checkGroupCount()
+        empty = main.TRUE if ( initial_groups_count == 0 ) else main.FALSE
+        utilities.assert_equal(
+            expect=main.FALSE,
+            actual=empty,
+            onpass="There are " + str(initial_groups_count) + " added groups",
+            onfail="There are no added groups",
+        )
+
+        no_pending_flows = utilities.retry(onos_cli.checkFlowsState,
+                                           [False, None],
+                                           kwargs={"isPENDING": False},
+                                           attempts=20,
+                                           getRetryingTime=True)
+
+        main.step("Verify there are no pending flows")
+        utilities.assert_equal(
+            expect=main.TRUE,
+            actual=no_pending_flows,
+            onpass="There are no pending flows",
+            onfail="There are pending flows",
+        )
+
+        no_pending_groups = utilities.retry(onos_cli.checkGroupsState,
+                                            [False, None],
+                                            kwargs={"isPENDING": False},
+                                            attempts=20,
+                                            getRetryingTime=True)
+
+        main.step("Verify there are no pending groups")
+        utilities.assert_equal(
+            expect=main.TRUE,
+            actual=no_pending_groups,
+            onpass="There are no pending groups",
+            onfail="There are pending groups",
+        )
+
+        main.step("Retrieving " + switch_to_kill + " master")
+        initial_master = onos_cli.getMaster("device:" + k8s_switch_node)
+        no_master = main.TRUE if ( initial_master is None ) else main.FALSE
+        utilities.assert_equal(
+            expect=main.FALSE,
+            actual=no_master,
+            onpass=initial_master + " is the master of " + switch_to_kill,
+            onfail="There is no master for " + switch_to_kill,
+        )
+
+        main.step("Set label to switch k8s node and kill Stratum")
+        # K8s node name correspond to the switch name in lowercase
+        utilities.assert_equal(
+            expect=main.TRUE,
+            actual=kubectl.kubectlSetLabel(
+                nodeName=k8s_switch_node,
+                label=k8s_label,
+                value=k8s_label_value_test,
+                kubeconfig=kubeconfig,
+                namespace=namespace,
+            ),
+            onpass="Label has been set correctly on node %s" % k8s_switch_node,
+            onfail="Label has not been set on node %s" % k8s_switch_node
+        )
+
+        try:
+            def checkNumberStratumPods(n_value):
+                pods = kubectl.kubectlGetPodNames(
+                    kubeconfig=kubeconfig,
+                    namespace=namespace,
+                    name="stratum"
+                )
+                main.log.info("PODS: " + str(pods))
+                return n_value == len(pods) if pods is not main.FALSE else False
+            # Execute the following in try/except/finally to be sure to restore the
+            # k8s label even in case of unhandled exception.
+
+            # Wait for stratum pod to be removed from the switch
+            removed = utilities.retry(checkNumberStratumPods,
+                                      False,
+                                      args=[n_switches - 1],
+                                      attempts=50)
+            main.log.info("Stratum has been removed from the switch? %s" % removed)
+
+            sleepTime = 20
+            switch_component = getattr(main, switch_to_kill)
+            main.log.info("Sleeping %s seconds for ONOS to react" % sleepTime)
+            time.sleep(sleepTime)
+
+            available = utilities.retry(SRStagingTest.switchIsConnected,
+                                        True,
+                                        args=[switch_component],
+                                        attempts=300,
+                                        getRetryingTime=True)
+            main.log.info("Switch %s is available in ONOS? %s" % (
+                switch_to_kill, available))
+            utilities.assert_equal(
+                expect=True,
+                actual=not available and removed,
+                onpass="Stratum was removed from switch k8s node",
+                onfail="Stratum was not removed from switch k8s node"
+            )
+
+            main.step("Verify there are no segmentrouting flows after the failure")
+            raw_flows = onos_cli.flows(device="device:" + k8s_switch_node)
+            sr_flows = main.TRUE if "segmentrouting" in raw_flows else main.FALSE
+            utilities.assert_equal(
+                expect=main.FALSE,
+                actual=sr_flows,
+                onpass="There are no segmentrouting flows",
+                onfail="There are segmentrouting flows",
+            )
+
+            main.step("Verify there are no segmentrouting groups after the failure")
+            raw_groups = onos_cli.groups(device="device:" + k8s_switch_node)
+            sr_groups = main.TRUE if "segmentrouting" in raw_groups else main.FALSE
+            utilities.assert_equal(
+                expect=main.FALSE,
+                actual=sr_groups,
+                onpass="There are no segmentrouting groups",
+                onfail="There are segmentrouting groups",
+            )
+
+            main.step("Verify " + initial_master + " is still the master of " + switch_to_kill)
+            after_master = onos_cli.getMaster("device:" + k8s_switch_node)
+            no_master = main.TRUE if ( initial_master is None ) else main.FALSE
+            utilities.assert_equal(
+                expect=main.FALSE,
+                actual=no_master,
+                onpass=initial_master + " is the master of " + switch_to_kill,
+                onfail="There is no master for " + switch_to_kill,
+            )
+
+            same_master = main.TRUE if ( initial_master == after_master ) else main.FALSE
+            utilities.assert_equal(
+                expect=main.TRUE,
+                actual=same_master,
+                onpass=initial_master + " is still the master of " + switch_to_kill,
+                onfail="Master for " + switch_to_kill + " is " + after_master,
+            )
+
+        except Exception as e:
+            main.log.error("Unhandled exception!")
+            main.log.error(e)
+        finally:
+            utilities.assert_equal(
+                expect=main.TRUE,
+                actual=kubectl.kubectlSetLabel(
+                    nodeName=k8s_switch_node,
+                    label=k8s_label,
+                    value=k8s_label_value_normal,
+                    kubeconfig=kubeconfig,
+                    namespace=namespace,
+                ),
+                onpass="Label has been set correctly on node %s" % k8s_switch_node,
+                onfail="Label has not been set on node %s" % k8s_switch_node
+            )
+
+            # Wait for stratum pod to be re-deployed on the switch
+            deployed = utilities.retry(checkNumberStratumPods,
+                                       False,
+                                       args=[n_switches],
+                                       attempts=50)
+            main.log.info("Stratum has been redeployed on the switch? %s" % deployed)
+
+            # Wait switch to be back in ONOS
+            available = utilities.retry(SRStagingTest.switchIsConnected,
+                                        False,
+                                        args=[switch_component],
+                                        sleep=2,
+                                        attempts=300,
+                                        getRetryingTime=True)
+            main.log.info("Switch %s is available in ONOS? %s" % (
+                switch_to_kill, available))
+            utilities.assert_equal(
+                expect=True,
+                actual=available and deployed,
+                onpass="Switch is back available in ONOS and stratum has been redeployed",
+                onfail="Switch is not available in ONOS, may influence subsequent tests!"
+            )
+
+        sleepTime = 10
+        main.log.info("Sleeping %s seconds for ONOS to react and assure flows/groups are ADDED" % sleepTime)
+        time.sleep(sleepTime)
+
+        main.step("Verify there are added flows after reboot")
+        after_flows_count = onos_cli.checkFlowCount()
+        empty = main.TRUE if ( after_flows_count == 0 ) else main.FALSE
+        utilities.assert_equal(
+            expect=main.FALSE,
+            actual=empty,
+            onpass="There are " + str(after_flows_count) + " added flows",
+            onfail="There are no added flows",
+        )
+
+        main.step("Verify there are added groups after reboot")
+        after_groups_count = onos_cli.checkGroupCount()
+        empty = main.TRUE if ( after_groups_count == 0 ) else main.FALSE
+        utilities.assert_equal(
+            expect=main.FALSE,
+            actual=empty,
+            onpass="There are " + str(after_groups_count) + " added groups",
+            onfail="There are no added groups",
+        )
+
+        no_pending_flows = utilities.retry(onos_cli.checkFlowsState,
+                                           [False, None],
+                                           kwargs={"isPENDING": False},
+                                           attempts=20,
+                                           getRetryingTime=True)
+
+        main.step("Verify there are no pending flows after reboot")
+        utilities.assert_equal(
+            expect=main.TRUE,
+            actual=no_pending_flows,
+            onpass="There are no pending flows",
+            onfail="There are pending flows",
+        )
+
+        no_pending_groups = utilities.retry(onos_cli.checkGroupsState,
+                                            [False, None],
+                                            kwargs={"isPENDING": False},
+                                            attempts=20,
+                                            getRetryingTime=True)
+
+        main.step("Verify there are no pending groups after reboot")
+        utilities.assert_equal(
+            expect=main.TRUE,
+            actual=no_pending_groups,
+            onpass="There are no pending groups",
+            onfail="There are pending groups",
+        )