【Ambari2.7.3源码分析】Agent命令状态上报器CommandStatusReporter

   日期:2020-07-18     浏览:154    评论:0    
核心提示:1、Agent init 7 threads还是一样的,Agent在这个InitializerModule.py中,init_threads()方法初始化了如下七个线程本文对命令状态上报器CommandStatusReporter进行了归纳总结2、CommandStatusReporter.py2.1、endless loop every 5 seconds default跟组件状态收集器ComponentStatusExecutor一样,在这里也是一个无限循环,每次循环间隔为5s在上图的_def sta

1、Agent init 7 threads

还是一样的,Agent在这个InitializerModule.py中,
init_threads()方法初始化了如下七个线程
本文对命令状态上报器CommandStatusReporter进行了归纳总结

2、CommandStatusReporter.py

2.1、endless loop every 5 seconds default

跟组件状态收集器ComponentStatusExecutor一样,在这里也是一个无限循环,每次循环间隔为5s

在上图的CommandStatusReporter.py的run方法无限循环里,调用了

commandStatuses.report()

commandStatuses由下可得

self.commandStatuses = initializer_module.commandStatuses

initializer_module.commandStatuses在Initializer_module由下可得

self.commandStatuses = CommandStatusDict(self)

所以,最终实际调用的是CommandStatusDict.run()方法

3、CommandStatuses.py

CommandStatuses.report()如下

def report(self):
 report = self.generate_report()

 if report:
   # 2MB is a max message size on the server side
   # MAX_REPORT_SIZE = 1950000
   for splitted_report in self.split_reports(report, CommandStatusDict.MAX_REPORT_SIZE):
     success, correlation_id = self.force_update_to_server(splitted_report)

     if success:
       self.server_responses_listener.listener_functions_on_success[correlation_id] = lambda headers, message: self.clear_reported_reports(splitted_report)

这里的逻辑分两部分

  • 1、通过CommandStatuses.generate_report()生成命令执行的report
  • 2、report按每2M的切片反馈给Ambari-Server,每个report切片汇报后如果Ambari-Server如果返回成功,则删除该report切片

这里主要看下CommandStatuses.generate_report()如何生成命令执行的report

3.1、CommandStatuses.generate_report()

  def generate_report(self):
    """
    Generates status reports about commands that are IN_PROGRESS, COMPLETE or
    FAILED. Statuses for COMPLETE or FAILED commands are forgotten after
    generation
    生成关于IN_PROGRESS、COMPLETE或FAILED命令的状态报告
    。COMPLETE或FAILED命令的状态生成后将被忘记

    """
    self.generated_reports = []

    with self.lock:
      result_reports = defaultdict(lambda:[])
      for key, item in self.current_state.items():

        logger.info('===gaofeng===CommandStatusDict===generate_report===key:%s====item:%s',key,item)
        logger.info('===gaofeng===CommandStatusDict===generate_report===key:%s====',key)
        logger.info('===gaofeng===CommandStatusDict===generate_report===item:%s',item)

        command = item[0]
        report = item[1]
        cluster_id = report['clusterId']
        # EXECUTION_COMMAND_GROUP = [execution, background_execution]
        if command['commandType'] in AgentCommand.EXECUTION_COMMAND_GROUP:
          # in_progress = 'IN_PROGRESS'
          if (report['status']) != CommandStatus.in_progress:
            #status不处于IN_PROGRESS状态
            result_reports[cluster_id].append(report)
            logger.info('===gaofeng===CommandStatusDict===generate_report==Not_in_progress_report')
            self.reported_reports.add(key)
          else:
            #status还处于IN_PROGRESS状态
            in_progress_report = self.generate_in_progress_report(command, report)
            logger.info('===gaofeng===CommandStatusDict===generate_report==in_progress_report:%s',in_progress_report)

            result_reports[cluster_id].append(in_progress_report)
        elif command['commandType'] == AgentCommand.auto_execution:
          logger.debug("AUTO_EXECUTION_COMMAND task deleted %s", command['commandId'])
          self.reported_reports.add(key)
          pass
      return result_reports

看日志后
key:1212-----其实就是界面的操作代表的任务id,taskID(对应ambar.db中host_role_command表的PRIMARY KEY)

item:如下图

command = item[0]
report = item[1]
所以report就是如下内容

{
	'status': 'IN_PROGRESS',
	'tmperr': '/var/lib/ambari-agent/data/errors-1212.txt',
	'tmpout': '/var/lib/ambari-agent/data/output-1212.txt',
	'roleCommand': u'CUSTOM_COMMAND',
	'structuredOut': '/var/lib/ambari-agent/data/structured-out-1212.json',
	'clusterId': u'2',
	'serviceName': u'YARN',
	'role': u'RESOURCEMANAGER',
	'actionId': u'125-0',
	'taskId': 1212
}

command = item[0]中的commandType为[execution, background_execution]其中的值时,就要判断report中的status了

  • status不处于IN_PROGRESS状态时,则将report追加到result_reports[cluster_id]中去,并且返回result_reports这个map,返回给CommandStatusDict.report(),看是否需要切片汇报给Ambari-server了
  • status处于IN_PROGRESS状态时,则需要调用CommandStatusDict.generate_in_progress_report()返回一个report后,也追加到result_reports中,返回给CommandStatusDict.report()

3.2、 CommandStatusDict.generate_in_progress_report()

上一小节说到如果status为IN_PROGRESS状态时,则需要调用如下方法

def generate_in_progress_report(self, command, report):
  """
  Reads stdout/stderr for IN_PROGRESS command from disk file
  and populates other fields of report.
  从磁盘文件中读取IN_PROGRESS命令的stdout/stderr
  并填充报告的其他字段。
  """
  #tmpout=/var/lib/ambari-agent/data/output-1212.txt
  #tmperr=/var/lib/ambari-agent/data/errors-1212.txt
  #structuredOut=/var/lib/ambari-agent/data/structured-out-1212.json
  files_to_read = [report['tmpout'], report['tmperr'], report['structuredOut']]
  files_content = ['...', '...', '{}']

  for i in xrange(len(files_to_read)):# 012
    filename = files_to_read[i]
    if os.path.exists(filename):
      with open(filename, 'r') as fp:# 只读模式打开每一个文件
        files_content[i] = fp.read()# 将每一个文件read出来放到files_content中
  # 将一个元组的元素赋给相应的变量
  tmpout, tmperr, tmpstructuredout = files_content

  grep = Grep()
  # OUTPUT_LAST_LINES=10,log_max_symbols_size=900000
  output = grep.tail_by_symbols(grep.tail(tmpout, Grep.OUTPUT_LAST_LINES), self.log_max_symbols_size)
  err = grep.tail_by_symbols(grep.tail(tmperr, Grep.OUTPUT_LAST_LINES), self.log_max_symbols_size)
  inprogress = self.generate_report_template(command)
  inprogress.update({
    'stdout': output,
    'stderr': err,
    'structuredOut': tmpstructuredout,
    'exitCode': 777,
    'status': CommandStatus.in_progress,
  })
  return inprogress

此方法较为简单,就是将下列文件内容读取出来,然后拼接一个模板generate_report_template(command)返回inprogress的report报告

tmpout=/var/lib/ambari-agent/data/output-1212.txt
tmperr=/var/lib/ambari-agent/data/errors-1212.txt
structuredOut=/var/lib/ambari-agent/data/structured-out-1212.json

最终的report我也打了log

in_progress_report如下图

可以知道,上图中的stderr、stdout对应ambari中的执行操作界面日志显示

4、force_update_to_server()

第3节说到report()中获得了report报告后,会将report按照每2M的的切片大小发送给server
调用的方法为
CommandStatusDict.force_update_to_server()

如下

def force_update_to_server(self, reports_dict):
   if not self.initializer_module.is_registered:
     return False, None

   try:
     #COMMANDS_STATUS_REPORTS_ENDPOINT = '/reports/commands_status'
     correlation_id = self.initializer_module.connection.send(message={'clusters':reports_dict}, destination=Constants.COMMANDS_STATUS_REPORTS_ENDPOINT, log_message_function=CommandStatusDict.log_sending)
     return True, correlation_id
   except ConnectionIsAlreadyClosed:
     return False, None

连接到server的destination=Constants.COMMANDS_STATUS_REPORTS_ENDPOINT
发送message={'clusters':reports_dict}

这里转到Ambari-Sever端代码

5、AgentReportsController

handleCommandReportStatus()方法即为上一节中所说的COMMANDS_STATUS_REPORTS_ENDPOINT
这里用到了注解,看路径就可以找到


他会接收report,然后返回response给agent

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服