mirror of https://github.com/apache/kafka.git
				
				
				
			
		
			
	
	
		
			682 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Python
		
	
	
	
		
		
			
		
	
	
			682 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Python
		
	
	
	
|  | #!/usr/bin/env python | ||
|  | 
 | ||
|  | # =================================== | ||
|  | # kafka_system_test_utils.py | ||
|  | # =================================== | ||
|  | 
 | ||
|  | import datetime | ||
|  | import inspect | ||
|  | import json | ||
|  | import logging | ||
|  | import os | ||
|  | import re | ||
|  | import subprocess | ||
|  | import sys | ||
|  | import time | ||
|  | import traceback | ||
|  | 
 | ||
|  | import system_test_utils | ||
|  | 
 | ||
|  | from datetime  import datetime | ||
|  | from time      import mktime | ||
|  | 
 | ||
|  | # ==================================================================== | ||
|  | # Two logging formats are defined in system_test/system_test_runner.py | ||
|  | # ==================================================================== | ||
|  | 
 | ||
|  | # 1. "namedLogger" is defined to log message in this format: | ||
|  | #    "%(asctime)s - %(levelname)s - %(message)s %(name_of_class)s" | ||
|  | #    usage: to log message and showing the class name of the message | ||
|  | 
 | ||
|  | logger     = logging.getLogger("namedLogger") | ||
|  | thisClassName = '(kafka_system_test_utils)' | ||
|  | d = {'name_of_class': thisClassName} | ||
|  | 
 | ||
|  | # 2. "anonymousLogger" is defined to log message in this format: | ||
|  | #    "%(asctime)s - %(levelname)s - %(message)s" | ||
|  | #    usage: to log message without showing class name and it's appropriate | ||
|  | #           for logging generic message such as "sleeping for 5 seconds" | ||
|  | 
 | ||
|  | anonLogger = logging.getLogger("anonymousLogger") | ||
|  | 
 | ||
|  | 
 | ||
|  | # ===================================== | ||
|  | # Sample usage of getting testcase env | ||
|  | # ===================================== | ||
|  | def get_testcase_env(testcaseEnv): | ||
|  |     anonLogger.info("================================================") | ||
|  |     anonLogger.info("systemTestBaseDir     : " + testcaseEnv.systemTestBaseDir) | ||
|  |     anonLogger.info("testSuiteBaseDir      : " + testcaseEnv.testSuiteBaseDir) | ||
|  |     anonLogger.info("testCaseBaseDir       : " + testcaseEnv.testCaseBaseDir) | ||
|  |     anonLogger.info("testCaseLogsDir       : " + testcaseEnv.testCaseLogsDir) | ||
|  |     anonLogger.info("userDefinedEnvVarDict : (testcaseEnv.userDefinedEnvVarDict)") | ||
|  |     anonLogger.info("================================================") | ||
|  | 
 | ||
|  | 
 | ||
|  | def get_testcase_config_log_dir_pathname(testcaseEnv, role, entityId, type): | ||
|  | 
 | ||
|  |     defaultLogDir = testcaseEnv.testCaseLogsDir + "/" + role + "-" + entityId | ||
|  | 
 | ||
|  |     # type is either "metrics" or "dashboards" or "default" | ||
|  |     if type == "metrics": | ||
|  |         return testcaseEnv.testCaseLogsDir + "/" + role + "-" + entityId + "/metrics" | ||
|  |     elif type == "default" : | ||
|  |         return testcaseEnv.testCaseLogsDir + "/" + role + "-" + entityId | ||
|  |     elif type == "dashboards": | ||
|  |         return testcaseEnv.testCaseLogsDir + "/dashboards" | ||
|  |     elif type == "config": | ||
|  |         return testcaseEnv.testCaseBaseDir + "/config" | ||
|  |     else: | ||
|  |         logger.error("unrecognized log directory type : " + type, extra=d) | ||
|  |         logger.error("returning default log dir : " + defaultLogDir, extra=d) | ||
|  |         return defaultLogDir | ||
|  | 
 | ||
|  | 
 | ||
|  | def generate_testcase_log_dirs(systemTestEnv, testcaseEnv): | ||
|  | 
 | ||
|  |     testcasePathName = testcaseEnv.testCaseBaseDir | ||
|  |     logger.debug("testcase pathname: " + testcasePathName, extra=d) | ||
|  | 
 | ||
|  |     if not os.path.exists(testcasePathName + "/config") : os.makedirs(testcasePathName + "/config") | ||
|  |     if not os.path.exists(testcasePathName + "/logs")   : os.makedirs(testcasePathName + "/logs") | ||
|  | 
 | ||
|  |     dashboardsPathName = testcaseEnv.testCaseLogsDir + "/dashboards" | ||
|  |     if not os.path.exists(dashboardsPathName) : os.makedirs(dashboardsPathName) | ||
|  | 
 | ||
|  |     for clusterEntityConfigDict in systemTestEnv.clusterEntityConfigDictList: | ||
|  |         entityId = clusterEntityConfigDict["entity_id"] | ||
|  |         role     = clusterEntityConfigDict["role"] | ||
|  | 
 | ||
|  |         logger.debug("entity_id : " + entityId, extra=d) | ||
|  |         logger.debug("role      : " + role,     extra=d) | ||
|  | 
 | ||
|  |         metricsPathName = get_testcase_config_log_dir_pathname(testcaseEnv, role, entityId, "metrics") | ||
|  |         if not os.path.exists(metricsPathName) : os.makedirs(metricsPathName) | ||
|  | 
 | ||
|  | 
 | ||
|  | def collect_logs_from_remote_hosts(systemTestEnv, testcaseEnv): | ||
|  |     anonLogger.info("================================================") | ||
|  |     anonLogger.info("collecting logs from remote machines") | ||
|  |     anonLogger.info("================================================") | ||
|  | 
 | ||
|  |     testCaseBaseDir = testcaseEnv.testCaseBaseDir | ||
|  | 
 | ||
|  |     for clusterEntityConfigDict in systemTestEnv.clusterEntityConfigDictList: | ||
|  |         hostname   = clusterEntityConfigDict["hostname"] | ||
|  |         entity_id  = clusterEntityConfigDict["entity_id"] | ||
|  |         role       = clusterEntityConfigDict["role"] | ||
|  | 
 | ||
|  |         logger.debug("entity_id : " + entity_id, extra=d) | ||
|  |         logger.debug("hostname  : " + hostname,  extra=d) | ||
|  |         logger.debug("role      : " + role,      extra=d) | ||
|  | 
 | ||
|  |         configPathName     = get_testcase_config_log_dir_pathname(testcaseEnv, role, entity_id, "config") | ||
|  |         metricsPathName    = get_testcase_config_log_dir_pathname(testcaseEnv, role, entity_id, "metrics") | ||
|  |         dashboardsPathName = get_testcase_config_log_dir_pathname(testcaseEnv, role, entity_id, "dashboards") | ||
|  | 
 | ||
|  |         cmdList = ["scp", | ||
|  |                    hostname + ":" + metricsPathName + "/*", | ||
|  |                    metricsPathName] | ||
|  |         cmdStr  = " ".join(cmdList) | ||
|  |         logger.debug("executing command [" + cmdStr + "]", extra=d) | ||
|  |         system_test_utils.sys_call(cmdStr) | ||
|  |   | ||
|  | 
 | ||
|  | def generate_testcase_log_dirs_in_remote_hosts(systemTestEnv, testcaseEnv): | ||
|  |     testCaseBaseDir = testcaseEnv.testCaseBaseDir | ||
|  | 
 | ||
|  |     for clusterEntityConfigDict in systemTestEnv.clusterEntityConfigDictList: | ||
|  |         hostname   = clusterEntityConfigDict["hostname"] | ||
|  |         entity_id  = clusterEntityConfigDict["entity_id"] | ||
|  |         role       = clusterEntityConfigDict["role"] | ||
|  | 
 | ||
|  |         logger.debug("entity_id : " + entity_id, extra=d) | ||
|  |         logger.debug("hostname  : " + hostname, extra=d) | ||
|  |         logger.debug("role      : " + role, extra=d) | ||
|  | 
 | ||
|  |         configPathName     = get_testcase_config_log_dir_pathname(testcaseEnv, role, entity_id, "config") | ||
|  |         metricsPathName    = get_testcase_config_log_dir_pathname(testcaseEnv, role, entity_id, "metrics") | ||
|  |         dashboardsPathName = get_testcase_config_log_dir_pathname(testcaseEnv, role, entity_id, "dashboards") | ||
|  | 
 | ||
|  |         cmdList = ["ssh " + hostname, | ||
|  |                    "'mkdir -p", | ||
|  |                    configPathName, | ||
|  |                    metricsPathName, | ||
|  |                    dashboardsPathName + "'"] | ||
|  |         cmdStr  = " ".join(cmdList) | ||
|  |         logger.debug("executing command [" + cmdStr + "]", extra=d) | ||
|  |         system_test_utils.sys_call(cmdStr) | ||
|  | 
 | ||
|  | 
 | ||
|  | def init_entity_props(systemTestEnv, testcaseEnv): | ||
|  |     clusterConfigsList  = systemTestEnv.clusterEntityConfigDictList | ||
|  |     testcaseConfigsList = testcaseEnv.testcaseConfigsList | ||
|  |     testcasePathName    = testcaseEnv.testCaseBaseDir | ||
|  | 
 | ||
|  |     # consumer config / log files location | ||
|  |     consEntityIdList   = system_test_utils.get_data_from_list_of_dicts( \ | ||
|  |                              clusterConfigsList, "role", "console_consumer", "entity_id") | ||
|  |     consLogList        = system_test_utils.get_data_from_list_of_dicts( \ | ||
|  |                              testcaseConfigsList, "entity_id", consEntityIdList[0], "log_filename") | ||
|  |     consLogPathname    = testcasePathName + "/logs/" + consLogList[0] | ||
|  |     consCfgList        = system_test_utils.get_data_from_list_of_dicts( \ | ||
|  |                              testcaseConfigsList, "entity_id", consEntityIdList[0], "config_filename") | ||
|  |     consCfgPathname    = testcasePathName + "/config/" + consCfgList[0] | ||
|  | 
 | ||
|  |     # producer config / log files location | ||
|  |     prodEntityIdList   = system_test_utils.get_data_from_list_of_dicts( \ | ||
|  |                              clusterConfigsList, "role", "producer_performance", "entity_id") | ||
|  |     prodLogList        = system_test_utils.get_data_from_list_of_dicts( \ | ||
|  |                              testcaseConfigsList, "entity_id", prodEntityIdList[0], "log_filename") | ||
|  |     prodLogPathname    = testcasePathName + "/logs/" + prodLogList[0] | ||
|  |     prodCfgList        = system_test_utils.get_data_from_list_of_dicts( \ | ||
|  |                              testcaseConfigsList, "entity_id", prodEntityIdList[0], "config_filename") | ||
|  |     prodCfgPathname    = testcasePathName + "/config/" + prodCfgList[0] | ||
|  | 
 | ||
|  |     testcaseEnv.userDefinedEnvVarDict["consumerLogPathName"]    = consLogPathname | ||
|  |     testcaseEnv.userDefinedEnvVarDict["consumerConfigPathName"] = consCfgPathname | ||
|  |     testcaseEnv.userDefinedEnvVarDict["producerLogPathName"]    = prodLogPathname | ||
|  |     testcaseEnv.userDefinedEnvVarDict["producerConfigPathName"] = prodCfgPathname | ||
|  | 
 | ||
|  | 
 | ||
|  | def copy_file_with_dict_values(srcFile, destFile, dictObj): | ||
|  |     infile  = open(srcFile, "r") | ||
|  |     inlines = infile.readlines() | ||
|  |     infile.close() | ||
|  | 
 | ||
|  |     outfile = open(destFile, 'w') | ||
|  |     for line in inlines: | ||
|  |         for key in dictObj.keys(): | ||
|  |             if (line.startswith(key + "=")): | ||
|  |                 line = key + "=" + dictObj[key] + "\n" | ||
|  |         outfile.write(line) | ||
|  |     outfile.close() | ||
|  | 
 | ||
|  | 
 | ||
|  | def start_metrics_collection(jmxHost, jmxPort, mBeanObjectName, mBeanAttributes, entityId, clusterEntityConfigDictList, testcaseEnv): | ||
|  |     logger.info("starting metrics collection on jmx port: " + jmxPort, extra=d) | ||
|  |     jmxUrl    = "service:jmx:rmi:///jndi/rmi://" + jmxHost + ":" + jmxPort + "/jmxrmi" | ||
|  |     kafkaHome = system_test_utils.get_data_by_lookup_keyval(clusterEntityConfigDictList, "entity_id", entityId, "kafka_home") | ||
|  |     javaHome  = system_test_utils.get_data_by_lookup_keyval(clusterEntityConfigDictList, "entity_id", entityId, "java_home") | ||
|  |     metricsPathName = get_testcase_config_log_dir_pathname(testcaseEnv, "broker", entityId, "metrics") | ||
|  | 
 | ||
|  |     startMetricsCmdList = ["ssh " + jmxHost, | ||
|  |                            "'JAVA_HOME=" + javaHome, | ||
|  |                            "JMX_PORT= " + kafkaHome + "/bin/kafka-run-class.sh kafka.tools.JmxTool", | ||
|  |                            "--jmx-url " + jmxUrl, | ||
|  |                            "--object-name " + mBeanObjectName + " &> ", | ||
|  |                            metricsPathName + "/metrics.csv & echo pid:$! > ", | ||
|  |                            metricsPathName + "/entity_pid'"] | ||
|  |     | ||
|  |     startMetricsCommand = " ".join(startMetricsCmdList)  | ||
|  |     logger.debug("executing command: [" + startMetricsCommand + "]", extra=d) | ||
|  |     system_test_utils.async_sys_call(startMetricsCommand) | ||
|  | 
 | ||
|  |     pidCmdStr = "ssh " + jmxHost + " 'cat " + metricsPathName + "/entity_pid'" | ||
|  |     logger.debug("executing command: [" + pidCmdStr + "]", extra=d) | ||
|  |     subproc = system_test_utils.sys_call_return_subproc(pidCmdStr) | ||
|  | 
 | ||
|  |     # keep track of the remote entity pid in a dictionary | ||
|  |     for line in subproc.stdout.readlines(): | ||
|  |         if line.startswith("pid"): | ||
|  |             line = line.rstrip('\n') | ||
|  |             logger.debug("found pid line: [" + line + "]", extra=d) | ||
|  |             tokens  = line.split(':') | ||
|  |             thisPid = tokens[1] | ||
|  |             testcaseEnv.entityParentPidDict[thisPid] = thisPid | ||
|  | 
 | ||
|  | 
 | ||
|  | def generate_overriden_props_files(testsuitePathname, testcaseEnv, systemTestEnv): | ||
|  |     logger.info("calling generate_properties_files", extra=d) | ||
|  | 
 | ||
|  |     clusterConfigsList = systemTestEnv.clusterEntityConfigDictList | ||
|  |     tcPathname    = testcaseEnv.testCaseBaseDir | ||
|  |     tcConfigsList = testcaseEnv.testcaseConfigsList | ||
|  | 
 | ||
|  |     cfgTemplatePathname = os.path.abspath(testsuitePathname + "/config") | ||
|  |     cfgDestPathname     = os.path.abspath(tcPathname + "/config") | ||
|  |     logger.info("config template (source) pathname : " + cfgTemplatePathname, extra=d) | ||
|  |     logger.info("testcase config (dest)   pathname : " + cfgDestPathname, extra=d) | ||
|  | 
 | ||
|  |     # loop through all zookeepers (if more than 1) to retrieve host and clientPort | ||
|  |     # to construct a zk.connect str for broker in the form of: | ||
|  |     # zk.connect=<host1>:<port2>,<host2>:<port2> | ||
|  |     zkConnectStr = "" | ||
|  |     zkDictList = system_test_utils.get_dict_from_list_of_dicts(clusterConfigsList, "role", "zookeeper") | ||
|  |     for zkDict in zkDictList: | ||
|  |         entityID       = zkDict["entity_id"] | ||
|  |         hostname       = zkDict["hostname"] | ||
|  |         clientPortList = system_test_utils.get_data_from_list_of_dicts(tcConfigsList, "entity_id", entityID, "clientPort") | ||
|  |         clientPort     = clientPortList[0] | ||
|  | 
 | ||
|  |         if ( zkConnectStr.__len__() == 0 ): | ||
|  |             zkConnectStr = hostname + ":" + clientPort | ||
|  |         else: | ||
|  |             zkConnectStr = zkConnectStr + "," + hostname + ":" + clientPort | ||
|  | 
 | ||
|  |     # for each entity in the cluster config | ||
|  |     for clusterCfg in clusterConfigsList: | ||
|  |         cl_entity_id = clusterCfg["entity_id"] | ||
|  | 
 | ||
|  |         for tcCfg in tcConfigsList: | ||
|  |             if (tcCfg["entity_id"] == cl_entity_id): | ||
|  | 
 | ||
|  |                 # copy the associated .properties template, update values, write to testcase_<xxx>/config | ||
|  | 
 | ||
|  |                 if ( clusterCfg["role"] == "broker" ): | ||
|  |                     tcCfg["zk.connect"] = zkConnectStr | ||
|  |                     copy_file_with_dict_values(cfgTemplatePathname + "/server.properties", \ | ||
|  |                                                cfgDestPathname + "/" + tcCfg["config_filename"], tcCfg) | ||
|  | 
 | ||
|  |                 elif ( clusterCfg["role"] == "zookeeper"): | ||
|  |                     copy_file_with_dict_values(cfgTemplatePathname + "/zookeeper.properties", \ | ||
|  |                                                cfgDestPathname + "/" + tcCfg["config_filename"], tcCfg) | ||
|  | 
 | ||
|  |                 elif ( clusterCfg["role"] == "producer_performance"): | ||
|  |                     tcCfg["brokerinfo"] = "zk.connect" + "=" + zkConnectStr | ||
|  |                     copy_file_with_dict_values(cfgTemplatePathname + "/producer_performance.properties", \ | ||
|  |                                                cfgDestPathname + "/" + tcCfg["config_filename"], tcCfg) | ||
|  | 
 | ||
|  |                 elif ( clusterCfg["role"] == "console_consumer"): | ||
|  |                     tcCfg["zookeeper"] = zkConnectStr | ||
|  |                     copy_file_with_dict_values(cfgTemplatePathname + "/console_consumer.properties", \ | ||
|  |                                                cfgDestPathname + "/" + tcCfg["config_filename"], tcCfg) | ||
|  |                 else: | ||
|  |                     print "    => ", tcCfg | ||
|  |                     print "UNHANDLED key" | ||
|  | 
 | ||
|  |     # scp updated config files to remote hosts | ||
|  |     scp_file_to_remote_host(clusterConfigsList, testcaseEnv) | ||
|  | 
 | ||
|  | 
 | ||
|  | def scp_file_to_remote_host(clusterEntityConfigDictList, testcaseEnv): | ||
|  | 
 | ||
|  |     testcaseConfigsList = testcaseEnv.testcaseConfigsList | ||
|  | 
 | ||
|  |     for clusterEntityConfigDict in clusterEntityConfigDictList: | ||
|  |         hostname         = clusterEntityConfigDict["hostname"] | ||
|  |         testcasePathName = testcaseEnv.testCaseBaseDir | ||
|  | 
 | ||
|  |         cmdStr = "scp " + testcasePathName + "/config/* " + hostname + ":" + testcasePathName + "/config" | ||
|  |         logger.debug("executing command [" + cmdStr + "]", extra=d) | ||
|  |         system_test_utils.sys_call(cmdStr) | ||
|  | 
 | ||
|  | 
 | ||
|  | def start_zookeepers(systemTestEnv, testcaseEnv): | ||
|  |     clusterEntityConfigDictList = systemTestEnv.clusterEntityConfigDictList | ||
|  | 
 | ||
|  |     zkEntityIdList = system_test_utils.get_data_from_list_of_dicts( \ | ||
|  |                          clusterEntityConfigDictList, "role", "zookeeper", "entity_id") | ||
|  | 
 | ||
|  |     for zkEntityId in zkEntityIdList: | ||
|  |         start_entity_in_background(systemTestEnv, testcaseEnv, zkEntityId) | ||
|  | 
 | ||
|  | 
 | ||
|  | def start_brokers(systemTestEnv, testcaseEnv): | ||
|  |     clusterEntityConfigDictList = systemTestEnv.clusterEntityConfigDictList | ||
|  | 
 | ||
|  |     brokerEntityIdList = system_test_utils.get_data_from_list_of_dicts( \ | ||
|  |                              clusterEntityConfigDictList, "role", "broker", "entity_id") | ||
|  | 
 | ||
|  |     for brokerEntityId in brokerEntityIdList: | ||
|  |         start_entity_in_background(systemTestEnv, testcaseEnv, brokerEntityId) | ||
|  | 
 | ||
|  | 
 | ||
|  | def get_leader_elected_log_line(systemTestEnv, testcaseEnv): | ||
|  | 
 | ||
|  |     logger.info("looking up leader...", extra=d) | ||
|  | 
 | ||
|  |     # keep track of leader related data in this dict such as broker id, | ||
|  |     # entity id and timestamp and return it to the caller function | ||
|  |     leaderDict = {}  | ||
|  | 
 | ||
|  |     clusterEntityConfigDictList = systemTestEnv.clusterEntityConfigDictList | ||
|  |     brokerEntityIdList = system_test_utils.get_data_from_list_of_dicts( \ | ||
|  |                              clusterEntityConfigDictList, "role", "broker", "entity_id") | ||
|  | 
 | ||
|  |     for brokerEntityId in brokerEntityIdList: | ||
|  | 
 | ||
|  |         hostname   = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                          clusterEntityConfigDictList, "entity_id", brokerEntityId, "hostname") | ||
|  |         logFile    = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                          testcaseEnv.testcaseConfigsList, "entity_id", brokerEntityId, "log_filename") | ||
|  | 
 | ||
|  |         leaderDict["entity_id"] = brokerEntityId | ||
|  |         leaderDict["hostname"]  = hostname | ||
|  | 
 | ||
|  |         logPathName = get_testcase_config_log_dir_pathname(testcaseEnv, "broker", brokerEntityId, "default") | ||
|  |         cmdStrList = ["ssh " + hostname, | ||
|  |                       "\"grep -i -h '" + testcaseEnv.userDefinedEnvVarDict["LEADER_ELECTION_COMPLETED_MSG"] + "' ", | ||
|  |                       logPathName + "/" + logFile + " | ", | ||
|  |                       "sort | tail -1\""] | ||
|  |         cmdStr     = " ".join(cmdStrList) | ||
|  | 
 | ||
|  |         logger.debug("executing command [" + cmdStr + "]", extra=d) | ||
|  |         subproc = system_test_utils.sys_call_return_subproc(cmdStr) | ||
|  |         for line in subproc.stdout.readlines(): | ||
|  | 
 | ||
|  |             line = line.rstrip('\n') | ||
|  | 
 | ||
|  |             if testcaseEnv.userDefinedEnvVarDict["LEADER_ELECTION_COMPLETED_MSG"] in line: | ||
|  |                 logger.info("found the log line : " + line, extra=d) | ||
|  |                 try: | ||
|  |                     matchObj    = re.match(testcaseEnv.userDefinedEnvVarDict["REGX_LEADER_ELECTION_PATTERN"], line) | ||
|  |                     datetimeStr = matchObj.group(1) | ||
|  |                     datetimeObj = datetime.strptime(datetimeStr, "%Y-%m-%d %H:%M:%S,%f") | ||
|  |                     unixTs = time.mktime(datetimeObj.timetuple()) + 1e-6*datetimeObj.microsecond | ||
|  |                     #print "{0:.3f}".format(unixTs) | ||
|  |                     leaderDict["timestamp"] = unixTs | ||
|  |                     leaderDict["brokerid"]  = matchObj.group(2) | ||
|  |                     leaderDict["topic"]     = matchObj.group(3) | ||
|  |                     leaderDict["partition"] = matchObj.group(4) | ||
|  |                 except: | ||
|  |                     logger.error("ERROR [unable to find matching leader details: Has the matching pattern changed?]", extra=d) | ||
|  |             #else: | ||
|  |             #    logger.debug("unmatched line found [" + line + "]", extra=d) | ||
|  | 
 | ||
|  |     return leaderDict | ||
|  | 
 | ||
|  | 
 | ||
|  | def start_entity_in_background(systemTestEnv, testcaseEnv, entityId): | ||
|  | 
 | ||
|  |     clusterEntityConfigDictList = systemTestEnv.clusterEntityConfigDictList | ||
|  | 
 | ||
|  |     # cluster configurations: | ||
|  |     hostname  = system_test_utils.get_data_by_lookup_keyval(clusterEntityConfigDictList, "entity_id", entityId, "hostname") | ||
|  |     role      = system_test_utils.get_data_by_lookup_keyval(clusterEntityConfigDictList, "entity_id", entityId, "role") | ||
|  |     kafkaHome = system_test_utils.get_data_by_lookup_keyval(clusterEntityConfigDictList, "entity_id", entityId, "kafka_home") | ||
|  |     javaHome  = system_test_utils.get_data_by_lookup_keyval(clusterEntityConfigDictList, "entity_id", entityId, "java_home") | ||
|  |     jmxPort   = system_test_utils.get_data_by_lookup_keyval(clusterEntityConfigDictList, "entity_id", entityId, "jmx_port") | ||
|  | 
 | ||
|  |     # testcase configurations: | ||
|  |     testcaseConfigsList = testcaseEnv.testcaseConfigsList | ||
|  |     clientPort = system_test_utils.get_data_by_lookup_keyval(testcaseConfigsList, "entity_id", entityId, "clientPort") | ||
|  |     configFile = system_test_utils.get_data_by_lookup_keyval(testcaseConfigsList, "entity_id", entityId, "config_filename") | ||
|  |     logFile    = system_test_utils.get_data_by_lookup_keyval(testcaseConfigsList, "entity_id", entityId, "log_filename") | ||
|  | 
 | ||
|  |     logger.info("starting " + role + " in host [" + hostname + "] on client port [" + clientPort + "]", extra=d) | ||
|  | 
 | ||
|  |     configPathName = get_testcase_config_log_dir_pathname(testcaseEnv, role, entityId, "config") | ||
|  |     logPathName    = get_testcase_config_log_dir_pathname(testcaseEnv, role, entityId, "default") | ||
|  | 
 | ||
|  |     if role == "zookeeper": | ||
|  |         cmdList = ["ssh " + hostname, | ||
|  |                   "'JAVA_HOME=" + javaHome, | ||
|  |                   kafkaHome + "/bin/zookeeper-server-start.sh ", | ||
|  |                   configPathName + "/" + configFile + " &> ", | ||
|  |                   logPathName + "/" + logFile + " & echo pid:$! > ", | ||
|  |                   logPathName + "/entity_" + entityId + "_pid'"] | ||
|  | 
 | ||
|  | 
 | ||
|  |         # construct zk.connect str and update it to testcaseEnv.userDefinedEnvVarDict.zkConnectStr | ||
|  |         if ( len(testcaseEnv.userDefinedEnvVarDict["zkConnectStr"]) > 0 ): | ||
|  |             testcaseEnv.userDefinedEnvVarDict["zkConnectStr"] = \ | ||
|  |                 testcaseEnv.userDefinedEnvVarDict["zkConnectStr"] + "," + hostname + ":" + clientPort | ||
|  |         else: | ||
|  |             testcaseEnv.userDefinedEnvVarDict["zkConnectStr"] = hostname + ":" + clientPort | ||
|  | 
 | ||
|  |     elif role == "broker": | ||
|  |         cmdList = ["ssh " + hostname, | ||
|  |                   "'JAVA_HOME=" + javaHome, | ||
|  |                   "JMX_PORT=" + jmxPort, | ||
|  |                   kafkaHome + "/bin/kafka-run-class.sh kafka.Kafka", | ||
|  |                   configPathName + "/" + configFile + " &> ", | ||
|  |                   logPathName + "/" + logFile + " & echo pid:$! > ", | ||
|  |                   logPathName + "/entity_" + entityId + "_pid'"] | ||
|  | 
 | ||
|  |     # it seems to be a better idea to launch producer & consumer in separate functions | ||
|  |     # elif role == "producer_performance": | ||
|  |     # elif role == "console_consumer": | ||
|  | 
 | ||
|  |     cmdStr = " ".join(cmdList) | ||
|  | 
 | ||
|  |     logger.debug("executing command: [" + cmdStr + "]", extra=d) | ||
|  |     system_test_utils.async_sys_call(cmdStr) | ||
|  |     time.sleep(5) | ||
|  | 
 | ||
|  |     pidCmdStr = "ssh " + hostname + " 'cat " + logPathName + "/entity_" + entityId + "_pid'" | ||
|  |     logger.debug("executing command: [" + pidCmdStr + "]", extra=d) | ||
|  |     subproc = system_test_utils.sys_call_return_subproc(pidCmdStr) | ||
|  | 
 | ||
|  |     # keep track of the remote entity pid in a dictionary | ||
|  |     for line in subproc.stdout.readlines(): | ||
|  |         if line.startswith("pid"): | ||
|  |             line = line.rstrip('\n') | ||
|  |             logger.debug("found pid line: [" + line + "]", extra=d) | ||
|  |             tokens = line.split(':') | ||
|  |             testcaseEnv.entityParentPidDict[entityId] = tokens[1] | ||
|  | 
 | ||
|  |     # if it is a broker, start metric collection | ||
|  |     if role == "broker": | ||
|  |         start_metrics_collection(hostname, jmxPort, "kafka:type=kafka.SocketServerStats", \ | ||
|  |             "AvgFetchRequestMs, AvgProduceRequestMs", entityId, clusterEntityConfigDictList, testcaseEnv) | ||
|  | 
 | ||
|  | 
 | ||
|  | def start_console_consumer(systemTestEnv, testcaseEnv): | ||
|  | 
 | ||
|  |     clusterEntityConfigDictList = systemTestEnv.clusterEntityConfigDictList | ||
|  | 
 | ||
|  |     consumerConfigList = system_test_utils.get_dict_from_list_of_dicts(clusterEntityConfigDictList, "role", "console_consumer") | ||
|  |     for consumerConfig in consumerConfigList: | ||
|  |         host              = consumerConfig["hostname"] | ||
|  |         entityId          = consumerConfig["entity_id"] | ||
|  |         kafkaHome         = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                                 clusterEntityConfigDictList, "entity_id", entityId, "kafka_home") | ||
|  |         javaHome          = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                                 clusterEntityConfigDictList, "entity_id", entityId, "java_home") | ||
|  |         kafkaRunClassBin  = kafkaHome + "/bin/kafka-run-class.sh" | ||
|  | 
 | ||
|  |         logger.info("starting console consumer", extra=d) | ||
|  | 
 | ||
|  |         consumerLogPathName = get_testcase_config_log_dir_pathname(testcaseEnv, "console_consumer", entityId, "default") + \ | ||
|  |                                   "/console_consumer.log" | ||
|  | 
 | ||
|  |         testcaseEnv.userDefinedEnvVarDict["consumerLogPathName"] = consumerLogPathName | ||
|  | 
 | ||
|  |         commandArgs = system_test_utils.convert_keyval_to_cmd_args(testcaseEnv.userDefinedEnvVarDict["consumerConfigPathName"]) | ||
|  |         cmdList = ["ssh " + host, | ||
|  |                    "'JAVA_HOME=" + javaHome, | ||
|  |                    kafkaRunClassBin + " kafka.consumer.ConsoleConsumer", | ||
|  |                    commandArgs + " &> " + consumerLogPathName + "'"] | ||
|  | 
 | ||
|  |         cmdStr = " ".join(cmdList) | ||
|  |         logger.debug("executing command: [" + cmdStr + "]", extra=d) | ||
|  |         system_test_utils.sys_call(cmdStr) | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | def start_producer_performance(systemTestEnv, testcaseEnv): | ||
|  | 
 | ||
|  |     clusterEntityConfigDictList = systemTestEnv.clusterEntityConfigDictList | ||
|  | 
 | ||
|  |     producerConfigList = system_test_utils.get_dict_from_list_of_dicts( \ | ||
|  |                              clusterEntityConfigDictList, "role", "producer_performance") | ||
|  |     for producerConfig in producerConfigList: | ||
|  |         host              = producerConfig["hostname"] | ||
|  |         entityId          = producerConfig["entity_id"] | ||
|  |         kafkaHome         = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                                 clusterEntityConfigDictList, "entity_id", entityId, "kafka_home") | ||
|  |         javaHome          = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                                 clusterEntityConfigDictList, "entity_id", entityId, "java_home") | ||
|  |         kafkaRunClassBin  = kafkaHome + "/bin/kafka-run-class.sh" | ||
|  | 
 | ||
|  |         logger.info("starting producer preformance", extra=d) | ||
|  | 
 | ||
|  |         producerLogPathName = get_testcase_config_log_dir_pathname(testcaseEnv, "producer_performance", entityId, "default") + \ | ||
|  |                                   "/producer_performance.log" | ||
|  | 
 | ||
|  |         testcaseEnv.userDefinedEnvVarDict["producerLogPathName"] = producerLogPathName | ||
|  | 
 | ||
|  |         commandArgs = system_test_utils.convert_keyval_to_cmd_args(testcaseEnv.userDefinedEnvVarDict["producerConfigPathName"]) | ||
|  |         cmdList = ["ssh " + host, | ||
|  |                    "'JAVA_HOME=" + javaHome, | ||
|  |                    kafkaRunClassBin + " kafka.perf.ProducerPerformance", | ||
|  |                    commandArgs + " &> " + producerLogPathName + "'"] | ||
|  | 
 | ||
|  |         cmdStr = " ".join(cmdList) | ||
|  |         logger.debug("executing command: [" + cmdStr + "]", extra=d) | ||
|  |         system_test_utils.sys_call(cmdStr)  | ||
|  | 
 | ||
|  | 
 | ||
|  | def stop_remote_entity(systemTestEnv, entityId, parentPid): | ||
|  |     clusterEntityConfigDictList = systemTestEnv.clusterEntityConfigDictList | ||
|  | 
 | ||
|  |     hostname  = system_test_utils.get_data_by_lookup_keyval(clusterEntityConfigDictList, "entity_id", entityId, "hostname") | ||
|  |     pidStack  = system_test_utils.get_remote_child_processes(hostname, parentPid) | ||
|  | 
 | ||
|  |     logger.info("terminating process id: " + parentPid + " in host: " + hostname, extra=d) | ||
|  |     system_test_utils.sigterm_remote_process(hostname, pidStack) | ||
|  |     time.sleep(1) | ||
|  |     system_test_utils.sigkill_remote_process(hostname, pidStack) | ||
|  | 
 | ||
|  | 
 | ||
|  | def create_topic(systemTestEnv, testcaseEnv): | ||
|  |     clusterEntityConfigDictList = systemTestEnv.clusterEntityConfigDictList | ||
|  | 
 | ||
|  |     prodPerfCfgList = system_test_utils.get_dict_from_list_of_dicts( \ | ||
|  |                           clusterEntityConfigDictList, "role", "producer_performance") | ||
|  |     prodPerfCfgDict = system_test_utils.get_dict_from_list_of_dicts( \ | ||
|  |                           testcaseEnv.testcaseConfigsList, "entity_id", prodPerfCfgList[0]["entity_id"]) | ||
|  |     prodTopicList   = prodPerfCfgDict[0]["topic"].split(',') | ||
|  | 
 | ||
|  |     zkEntityId      = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                           clusterEntityConfigDictList, "role", "zookeeper", "entity_id") | ||
|  |     zkHost          = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                           clusterEntityConfigDictList, "role", "zookeeper", "hostname") | ||
|  |     kafkaHome       = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                           clusterEntityConfigDictList, "entity_id", zkEntityId, "kafka_home") | ||
|  |     javaHome        = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                           clusterEntityConfigDictList, "entity_id", zkEntityId, "java_home") | ||
|  |     createTopicBin  = kafkaHome + "/bin/kafka-create-topic.sh" | ||
|  | 
 | ||
|  |     logger.info("zkEntityId : " + zkEntityId, extra=d) | ||
|  |     logger.info("createTopicBin : " + createTopicBin, extra=d) | ||
|  | 
 | ||
|  |     for topic in prodTopicList: | ||
|  |         logger.info("creating topic: [" + topic + "] at: [" + testcaseEnv.userDefinedEnvVarDict["zkConnectStr"] + "]", extra=d)  | ||
|  |         cmdList = ["ssh " + zkHost, | ||
|  |                    "'JAVA_HOME=" + javaHome, | ||
|  |                    createTopicBin, | ||
|  |                    " --topic "     + topic, | ||
|  |                    " --zookeeper " + testcaseEnv.userDefinedEnvVarDict["zkConnectStr"], | ||
|  |                    " --replica "   + testcaseEnv.testcaseArgumentsDict["replica_factor"], | ||
|  |                    " --partition " + testcaseEnv.testcaseArgumentsDict["num_partition"] + " &> ", | ||
|  |                    testcaseEnv.testCaseBaseDir + "/logs/create_topic.log'"] | ||
|  | 
 | ||
|  |         cmdStr = " ".join(cmdList) | ||
|  |         logger.debug("executing command: [" + cmdStr + "]", extra=d) | ||
|  |         subproc = system_test_utils.sys_call_return_subproc(cmdStr) | ||
|  | 
 | ||
|  | 
 | ||
|  | def get_message_id(logPathName): | ||
|  |     logLines      = open(logPathName, "r").readlines() | ||
|  |     messageIdList = [] | ||
|  | 
 | ||
|  |     for line in logLines: | ||
|  |         if not "MessageID" in line: | ||
|  |             continue | ||
|  |         else: | ||
|  |             matchObj = re.match('.*MessageID:(.*?):', line) | ||
|  |             messageIdList.append( matchObj.group(1) ) | ||
|  | 
 | ||
|  |     return messageIdList | ||
|  | 
 | ||
|  | 
 | ||
|  | def validate_data_matched(systemTestEnv, testcaseEnv): | ||
|  |     validationStatusDict        = testcaseEnv.validationStatusDict | ||
|  |     clusterEntityConfigDictList = systemTestEnv.clusterEntityConfigDictList | ||
|  | 
 | ||
|  |     producerEntityId = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                            clusterEntityConfigDictList, "role", "producer_performance", "entity_id") | ||
|  |     consumerEntityId = system_test_utils.get_data_by_lookup_keyval( \ | ||
|  |                            clusterEntityConfigDictList, "role", "console_consumer", "entity_id") | ||
|  |     msgIdMissingInConsumerLogPathName = get_testcase_config_log_dir_pathname( \ | ||
|  |                            testcaseEnv, "console_consumer", consumerEntityId, "default") + \ | ||
|  |                            "/msg_id_missing_in_consumer.log" | ||
|  | 
 | ||
|  |     producerMsgIdList  = get_message_id(testcaseEnv.userDefinedEnvVarDict["producerLogPathName"]) | ||
|  |     consumerMsgIdList  = get_message_id(testcaseEnv.userDefinedEnvVarDict["consumerLogPathName"]) | ||
|  |     producerMsgIdSet   = set(producerMsgIdList) | ||
|  |     consumerMsgIdSet   = set(consumerMsgIdList) | ||
|  | 
 | ||
|  |     missingMsgIdInConsumer = producerMsgIdSet - consumerMsgIdSet | ||
|  | 
 | ||
|  |     outfile = open(msgIdMissingInConsumerLogPathName, "w") | ||
|  |     for id in missingMsgIdInConsumer: | ||
|  |         outfile.write(id + "\n") | ||
|  |     outfile.close() | ||
|  | 
 | ||
|  |     logger.info("no. of unique messages sent from publisher  : " + str(len(producerMsgIdSet)), extra=d) | ||
|  |     logger.info("no. of unique messages received by consumer : " + str(len(producerMsgIdSet)), extra=d) | ||
|  | 
 | ||
|  |     if ( len(missingMsgIdInConsumer) == 0 and len(producerMsgIdSet) > 0 ): | ||
|  |         validationStatusDict["Validate for data matched"] = "PASSED" | ||
|  |         return True | ||
|  |     else: | ||
|  |         validationStatusDict["Validate for data matched"] = "FAILED" | ||
|  |         logger.info("See " + msgIdMissingInConsumerLogPathName + " for missing MessageID", extra=d) | ||
|  |         return False | ||
|  |       | ||
|  | 
 | ||
|  | def validate_leader_election_successful(testcaseEnv, leaderDict, validationStatusDict): | ||
|  | 
 | ||
|  |     if ( len(leaderDict) > 0 ): | ||
|  |         try: | ||
|  |             leaderBrokerId = leaderDict["brokerid"] | ||
|  |             leaderEntityId = leaderDict["entity_id"] | ||
|  |             leaderPid      = testcaseEnv.entityParentPidDict[leaderEntityId] | ||
|  |             hostname       = leaderDict["hostname"] | ||
|  | 
 | ||
|  |             logger.info("found leader in entity [" + leaderEntityId + "] with brokerid [" + \ | ||
|  |                 leaderBrokerId + "] for partition [" + leaderDict["partition"] + "]", extra=d) | ||
|  |             validationStatusDict["Validate leader election successful"] = "PASSED" | ||
|  |             return True | ||
|  |         except Exception, e: | ||
|  |             logger.error("leader info not completed:", extra=d) | ||
|  |             validationStatusDict["Validate leader election successful"] = "FAILED" | ||
|  |             print leaderDict | ||
|  |             print e | ||
|  |             return False | ||
|  |     else: | ||
|  |         validationStatusDict["Validate leader election successful"] = "FAILED" | ||
|  |         return False | ||
|  | 
 | ||
|  | 
 | ||
|  | def cleanup_data_at_remote_hosts(systemTestEnv, testcaseEnv): | ||
|  | 
 | ||
|  |     clusterEntityConfigDictList = systemTestEnv.clusterEntityConfigDictList | ||
|  |     testcaseConfigsList         = testcaseEnv.testcaseConfigsList | ||
|  | 
 | ||
|  |     for clusterEntityConfigDict in systemTestEnv.clusterEntityConfigDictList: | ||
|  | 
 | ||
|  |         hostname         = clusterEntityConfigDict["hostname"] | ||
|  |         entityId         = clusterEntityConfigDict["entity_id"] | ||
|  |         role             = clusterEntityConfigDict["role"] | ||
|  |         #testcasePathName = testcaseEnv.testcaseBaseDir | ||
|  |         cmdStr           = "" | ||
|  |         dataDir          = "" | ||
|  | 
 | ||
|  |         logger.info("cleaning up data dir on host: [" + hostname + "]", extra=d) | ||
|  | 
 | ||
|  |         if role == 'zookeeper': | ||
|  |             dataDir = system_test_utils.get_data_by_lookup_keyval(testcaseConfigsList, "entity_id", entityId, "dataDir") | ||
|  |         elif role == 'broker': | ||
|  |             dataDir = system_test_utils.get_data_by_lookup_keyval(testcaseConfigsList, "entity_id", entityId, "log.dir") | ||
|  |         else: | ||
|  |             logger.info("skipping role [" + role + "] on host : [" + hostname + "]", extra=d) | ||
|  |             continue | ||
|  | 
 | ||
|  |         cmdStr  = "ssh " + hostname + " 'rm -r " + dataDir + "/*'" | ||
|  | 
 | ||
|  |         if not dataDir.startswith("/tmp"): | ||
|  |             logger.warn("possible destructive command [" + cmdStr + "]", extra=d) | ||
|  |             logger.warn("check config file: system_test/cluster_config.properties", extra=d) | ||
|  |             logger.warn("aborting test...", extra=d) | ||
|  |             sys.exit(1) | ||
|  | 
 | ||
|  |         logger.debug("executing command [" + cmdStr + "]", extra=d) | ||
|  |         system_test_utils.sys_call(cmdStr) | ||
|  | 
 | ||
|  |      | ||
|  | 
 |