HC Test: Update list of Honeycomb BGP modules
[csit.git] / resources / libraries / python / honeycomb / HoneycombSetup.py
index 55eb64e..7c3831c 100644 (file)
@@ -13,6 +13,9 @@
 
 """Implementation of keywords for Honeycomb setup."""
 
+from json import loads
+from time import time, sleep
+
 from ipaddress import IPv6Address, AddressValueError
 
 from robot.api import logger
@@ -134,106 +137,87 @@ class HoneycombSetup(object):
                     node['host']))
 
     @staticmethod
-    def check_honeycomb_startup_state(*nodes):
-        """Check state of Honeycomb service during startup on specified nodes.
-
-        Reads html path from template file oper_vpp_version.url.
+    def check_honeycomb_startup_state(node, timeout=360, retries=20,
+                                      interval=15):
+        """Repeatedly check the status of Honeycomb startup until it is fully
+        started or until timeout or max retries is reached.
 
-        Honeycomb nodes reply with connection refused or the following status
-        codes depending on startup progress: codes 200, 401, 403, 404, 500, 503
+        :param node: Honeycomb node.
+        :param timeout: Timeout value in seconds.
+        :param retries: Max number of retries.
+        :param interval: Interval between checks, in seconds.
+        :type node: dict
+        :type timeout: int
+        :type retries: int
+        :type interval: int
+        :raises HoneycombError: If the Honeycomb process IP cannot be found,
+        or if timeout or number of retries is exceeded."""
 
-        :param nodes: List of DUT nodes starting Honeycomb.
-        :type nodes: list
-        :return: True if all GETs returned code 200(OK).
-        :rtype bool
-        """
-        path = HcUtil.read_path_from_url_file("oper_vpp_version")
-        expected_status_codes = (HTTPCodes.UNAUTHORIZED,
-                                 HTTPCodes.FORBIDDEN,
-                                 HTTPCodes.NOT_FOUND,
-                                 HTTPCodes.SERVICE_UNAVAILABLE,
-                                 HTTPCodes.INTERNAL_SERVER_ERROR)
+        ssh = SSH()
+        ssh.connect(node)
 
-        for node in nodes:
-            if node['type'] == NodeType.DUT:
-                HoneycombSetup.print_ports(node)
-                try:
-                    status_code, _ = HTTPRequest.get(node, path,
-                                                     enable_logging=False)
-                except HTTPRequestError:
-                    ssh = SSH()
-                    ssh.connect(node)
-                    ret_code, _, _ = ssh.exec_command_sudo(
-                        "tail -n 100 /var/log/syslog")
-                    if ret_code != 0:
-                        # It's probably Centos
-                        ssh.exec_command_sudo("tail -n 100 /var/log/messages")
-                    raise
-                if status_code == HTTPCodes.OK:
-                    logger.info("Honeycomb on node {0} is up and running".
-                                format(node['host']))
-                elif status_code in expected_status_codes:
-                    if status_code == HTTPCodes.UNAUTHORIZED:
-                        logger.info('Unauthorized. If this triggers keyword '
-                                    'timeout, verify Honeycomb username and '
-                                    'password.')
-                    raise HoneycombError('Honeycomb on node {0} running but '
-                                         'not yet ready.'.format(node['host']),
-                                         enable_logging=False)
-                else:
-                    raise HoneycombError('Unexpected return code: {0}.'.
-                                         format(status_code))
+        count = 0
+        start = time()
+        while time() - start < timeout and count < retries:
+            count += 1
 
-                status_code, _ = HcUtil.get_honeycomb_data(
+            try:
+                status_code_version, _ = HcUtil.get_honeycomb_data(
+                    node, "oper_vpp_version")
+                status_code_if_cfg, _ = HcUtil.get_honeycomb_data(
                     node, "config_vpp_interfaces")
-                if status_code != HTTPCodes.OK:
-                    raise HoneycombError('Honeycomb on node {0} running but '
-                                         'not yet ready.'.format(node['host']),
-                                         enable_logging=False)
-        return True
+                status_code_if_oper, _ = HcUtil.get_honeycomb_data(
+                    node, "oper_vpp_interfaces")
+            except HTTPRequestError:
+                sleep(interval)
+                continue
+            if status_code_if_cfg == HTTPCodes.OK\
+                    and status_code_if_cfg == HTTPCodes.OK\
+                    and status_code_if_oper == HTTPCodes.OK:
+                logger.info("Check successful, Honeycomb is up and running.")
+                break
+            else:
+                logger.debug(
+                    "Attempt ${count} failed on Restconf check. Status codes:\n"
+                    "Version: {version}\n"
+                    "Interface config: {if_cfg}\n"
+                    "Interface operational: {if_oper}".format(
+                        count=count,
+                        version=status_code_version,
+                        if_cfg=status_code_if_cfg,
+                        if_oper=status_code_if_oper))
+                sleep(interval)
+                continue
+        else:
+            _, vpp_status, _ = ssh.exec_command("sudo service vpp status")
+            raise HoneycombError(
+                "Timeout or max retries exceeded. Status of VPP:\n"
+                "{vpp_status}".format(vpp_status=vpp_status))
 
     @staticmethod
-    def check_honeycomb_shutdown_state(*nodes):
+    def check_honeycomb_shutdown_state(node):
         """Check state of Honeycomb service during shutdown on specified nodes.
 
         Honeycomb nodes reply with connection refused or the following status
         codes depending on shutdown progress: codes 200, 404.
 
-        :param nodes: List of DUT nodes stopping Honeycomb.
-        :type nodes: list
+        :param node: List of DUT nodes stopping Honeycomb.
+        :type node: dict
         :return: True if all GETs fail to connect.
         :rtype bool
         """
-        cmd = "ps -ef | grep -v grep | grep honeycomb"
-        for node in nodes:
-            if node['type'] == NodeType.DUT:
-                try:
-                    status_code, _ = HTTPRequest.get(node, '/index.html',
-                                                     enable_logging=False)
-                    if status_code == HTTPCodes.OK:
-                        raise HoneycombError('Honeycomb on node {0} is still '
-                                             'running.'.format(node['host']),
-                                             enable_logging=False)
-                    elif status_code == HTTPCodes.NOT_FOUND:
-                        raise HoneycombError('Honeycomb on node {0} is shutting'
-                                             ' down.'.format(node['host']),
-                                             enable_logging=False)
-                    else:
-                        raise HoneycombError('Unexpected return code: {0}.'.
-                                             format(status_code))
-                except HTTPRequestError:
-                    logger.debug('Connection refused, checking the process '
-                                 'state ...')
-                    ssh = SSH()
-                    ssh.connect(node)
-                    (ret_code, _, _) = ssh.exec_command_sudo(cmd)
-                    if ret_code == 0:
-                        raise HoneycombError('Honeycomb on node {0} is still '
-                                             'running.'.format(node['host']),
-                                             enable_logging=False)
-                    else:
-                        logger.info("Honeycomb on node {0} has stopped".
-                                    format(node['host']))
+        cmd = "pgrep honeycomb"
+
+        ssh = SSH()
+        ssh.connect(node)
+        (ret_code, _, _) = ssh.exec_command_sudo(cmd)
+        if ret_code == 0:
+            raise HoneycombError('Honeycomb on node {0} is still '
+                                 'running.'.format(node['host']),
+                                 enable_logging=False)
+        else:
+            logger.info("Honeycomb on node {0} has stopped".
+                        format(node['host']))
         return True
 
     @staticmethod
@@ -309,7 +293,8 @@ class HoneycombSetup(object):
                 "which java",
                 "java -version",
                 "dpkg --list | grep openjdk",
-                "ls -la /opt/honeycomb")
+                "ls -la /opt/honeycomb",
+                "cat /opt/honeycomb/modules/*module-config")
 
         for node in nodes:
             if node['type'] == NodeType.DUT:
@@ -381,27 +366,39 @@ class HoneycombSetup(object):
          """
 
         disabled_features = {
-            "NSH": "io.fd.hc2vpp.vppnsh.impl.VppNshModule"
+            "NSH": ["io.fd.hc2vpp.vppnsh.impl.VppNshModule"],
+            "BGP": ["io.fd.hc2vpp.bgp.inet.BgpInetModule",
+                    "io.fd.honeycomb.infra.bgp.BgpModule",
+                    "io.fd.honeycomb.infra.bgp.BgpReadersModule",
+                    "io.fd.honeycomb.infra.bgp.BgpWritersModule",
+                    "io.fd.honeycomb.northbound.bgp.extension.InetModule",
+                    "io.fd.honeycomb.northbound.bgp.extension.EvpnModule",
+                    "io.fd.honeycomb.northbound.bgp.extension.L3VpnV4Module",
+                    "io.fd.honeycomb.northbound.bgp.extension.L3VpnV6Module",
+                    "io.fd.honeycomb.northbound.bgp.extension."
+                    "LabeledUnicastModule",
+                    "io.fd.honeycomb.northbound.bgp.extension.LinkstateModule"]
         }
 
         ssh = SSH()
         ssh.connect(node)
 
         if feature in disabled_features.keys():
-            # uncomment by replacing the entire line
-            find = replace = "{0}".format(disabled_features[feature])
-            if disable:
-                replace = "// {0}".format(find)
-
-            argument = '"/{0}/c\\ {1}"'.format(find, replace)
-            path = "{0}/modules/*module-config"\
-                .format(Const.REMOTE_HC_DIR)
-            command = "sed -i {0} {1}".format(argument, path)
-
-            (ret_code, _, stderr) = ssh.exec_command_sudo(command)
-            if ret_code != 0:
-                raise HoneycombError("Failed to modify configuration on "
-                                     "node {0}, {1}".format(node, stderr))
+            # for every module, uncomment by replacing the entire line
+            for item in disabled_features[feature]:
+                find = replace = "{0}".format(item)
+                if disable:
+                    replace = "// {0}".format(find)
+
+                argument = '"/{0}/c\\ {1}"'.format(find, replace)
+                path = "{0}/modules/*module-config"\
+                    .format(Const.REMOTE_HC_DIR)
+                command = "sed -i {0} {1}".format(argument, path)
+
+                (ret_code, _, stderr) = ssh.exec_command_sudo(command)
+                if ret_code != 0:
+                    raise HoneycombError("Failed to modify configuration on "
+                                         "node {0}, {1}".format(node, stderr))
         else:
             raise HoneycombError(
                 "Unrecognized feature {0}.".format(feature))
@@ -461,10 +458,11 @@ class HoneycombSetup(object):
         ssh = SSH()
         ssh.connect(node)
 
-        cmd = "cp -r {src}/*karaf_{odl_name}* {dst}".format(
-            src=src_path, odl_name=odl_name, dst=dst_path)
+        cmd = "sudo rm -rf {dst}/*karaf_{odl_name} && " \
+              "cp -r {src}/*karaf_{odl_name}* {dst}".format(
+                  src=src_path, odl_name=odl_name, dst=dst_path)
 
-        ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=120)
+        ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=180)
         if int(ret_code) != 0:
             raise HoneycombError(
                 "Failed to copy ODL client on node {0}".format(node["host"]))
@@ -512,11 +510,13 @@ class HoneycombSetup(object):
         ssh.connect(node)
 
         cmd = "{path}/*karaf*/bin/client -u karaf feature:install " \
-              "odl-restconf-all odl-netconf-connector-all".format(path=path)
+              "odl-restconf-all " \
+              "odl-netconf-connector-all " \
+              "odl-netconf-topology".format(path=path)
         for feature in features:
             cmd += " {0}".format(feature)
 
-        ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=180)
+        ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=250)
 
         if int(ret_code) != 0:
             raise HoneycombError("Feature install did not succeed.")
@@ -598,14 +598,21 @@ class HoneycombSetup(object):
             "odl_client/odl_netconf_connector")
 
         url_file = "{0}/{1}".format(Const.RESOURCES_TPL_HC,
-                                    "odl_client/mount_honeycomb.xml")
+                                    "odl_client/mount_honeycomb.json")
 
         with open(url_file) as template:
             data = template.read()
 
+        data = loads(data)
+
         status_code, _ = HTTPRequest.post(
-            node, path, headers={"Content-Type": "application/xml"},
-            payload=data, timeout=10, enable_logging=False)
+            node,
+            path,
+            headers={"Content-Type": "application/json",
+                     "Accept": "text/plain"},
+            json=data,
+            timeout=10,
+            enable_logging=False)
 
         if status_code == HTTPCodes.OK:
             logger.info("ODL mount point configured successfully.")
@@ -643,21 +650,7 @@ class HoneycombSetup(object):
 
         logger.info("ODL client service stopped.")
 
-    @staticmethod
-    def stop_vpp_service(node):
-        """Stop VPP service on the specified node.
 
-        :param node: VPP node.
-        :type node: dict
-        :raises RuntimeError: If VPP fails to stop.
-        """
-
-        ssh = SSH()
-        ssh.connect(node)
-        cmd = "service vpp stop"
-        ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=80)
-        if int(ret_code) != 0:
-            logger.debug("VPP service refused to shut down.")
 
 class HoneycombStartupConfig(object):
     """Generator for Honeycomb startup configuration.
@@ -665,8 +658,7 @@ class HoneycombStartupConfig(object):
     def __init__(self):
         """Initializer."""
 
-        self.template = """
-        #!/bin/sh -
+        self.template = """#!/bin/sh -
         STATUS=100
 
         while [ $STATUS -eq 100 ]
@@ -681,7 +673,7 @@ class HoneycombStartupConfig(object):
         done
         """
 
-        self.java_call = "{scheduler} {affinity} java {jit_mode} {params}"
+        self.java_call = "{scheduler} {affinity} java{jit_mode}{params}"
 
         self.scheduler = ""
         self.core_affinity = ""
@@ -751,9 +743,9 @@ class HoneycombStartupConfig(object):
         :type jit_mode: str
         """
 
-        modes = {"client": "-client",  # Default
-                 "server": "-server",  # Higher performance but longer warmup
-                 "classic": "-classic"  # Disables JIT compiler
+        modes = {"client": " -client",  # Default
+                 "server": " -server",  # Higher performance but longer warmup
+                 "classic": " -classic"  # Disables JIT compiler
                 }
 
         self.jit_mode = modes[jit_mode]
@@ -790,3 +782,10 @@ class HoneycombStartupConfig(object):
         architectures."""
 
         self.params += " -XX:+UseNUMA -XX:+UseParallelGC"
+
+    def set_ssh_security_provider(self):
+        """Disables BouncyCastle for SSHD."""
+        # Workaround for issue described in:
+        # https://wiki.fd.io/view/Honeycomb/Releases/1609/Honeycomb_and_ODL
+
+        self.params += " -Dorg.apache.sshd.registerBouncyCastle=false"