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)):# 0,1,2
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