def get_system(host, type_): """获取单个节点系统信息 由于每个Host仅可属于一个集群,故只需提供Host而无需提供集群ID :param host: 要查询的节点Host :param type_: 查询种类 :return: [] or None """ system_list = None _allow_type = ['mem', 'disk', 'cpu'] if type_ not in _allow_type: return {'message': 'type error', 'status': False} cluster_status = Gl.get_value('CLUSTER_STATUS_VAR', {}) cluster_all_hosts = Gl.get_value('CLUSTER_ALL_HOSTS_VAR', []) if host not in cluster_all_hosts: _logger.write('节点Host: \'' + host + '\'无效', level='warn') return {'message': 'host not found', 'status': False} if host not in cluster_status or not cluster_status.get(host).get( 'status'): return {'message': 'host unavailable', 'status': False} rq_url = _root_url.format(host=host, port=SLAVE_SERVICE_PORT_VAR, root_path='system', type_path='') rq_args = {'type': type_} try: rq_obj = requests.get(rq_url, params=rq_args) system_list = json.loads(rq_obj.text) except ConnectionError: _logger.write(str(host) + '连接失败', 'warn') system_list = {'message': 'host connect fail', 'status': False} return system_list
def choose_free_cluster(): """选择集群 返回一个空闲集群id及其下属的所有节点信息(host, username, password) 本方法为原子方法,同时仅允许一个线程操作本方法 :return: 字典形式:{'cluster_id': '', 'node': [{'host': '', 'account': '', 'password': '', 'name': ''}], 'describe': ''} or None """ Choose._choose_lock.acquire() cluster_all_info = Gl.get_value('CLUSTER_ALL_INFO_VAR', {}) cluster_free_id = Gl.get_value('CLUSTER_FREE_ID_VAR', []) cluster = {} try: cluster_id = cluster_free_id.pop() cluster['cluster_id'] = cluster_id cluster['node'] = cluster_all_info.get(cluster_id).get('node') cluster['describe'] = cluster_all_info.get(cluster_id).get( 'describe') _logger.write('集群选择成功.集群ID: ', level='info') except IndexError: cluster = None _logger.write('集群选择失败: 无空闲集群', level='warn') Gl.set_value('CLUSTER_FREE_ID_VAR', cluster_free_id) Choose._choose_lock.release() return cluster
def get_container(host): """获取单个节点容器信息 由于每个Host仅可属于一个集群,故只需提供Host而无需提供集群ID :param host: 要查询的节点Host :return: { "message":[ { message: { 'id': 容器id, 'short_id': 容器短id, 'status': 容器状态, 'paused': 容器是否暂停, 'running': 容器是否在运行, 'finishedAt': 容器退出时间, 'startedAt': 容器开始时间, 'created': 容器创建日期 'image': 容器依赖镜像, 'exit_time': 容器退出时间. }, }, { ... },... ], "status": bool, "refresh": , "url": } or { "message": error_reason, "status": } """ cluster_status = Gl.get_value('CLUSTER_STATUS_VAR', {}) cluster_all_hosts = Gl.get_value('CLUSTER_ALL_HOSTS_VAR', []) if host not in cluster_all_hosts: _logger.write('节点Host: \'' + host + '\'无效', level='warn') return {'message': 'host unavailable', 'status': False} if host not in cluster_status or not cluster_status.get(host).get( 'status'): return {'message': 'type error', 'status': False} rq_url = _root_url.format(host=host, port=SLAVE_SERVICE_PORT_VAR, root_path='container', type_path='_all') try: rq_obj = requests.get(rq_url) containers_list = json.loads(rq_obj.text) except ConnectionError: _logger.write(str(host) + '连接失败', 'warn') return {'message': 'node connect fail', 'status': False} return containers_list
def check_timeout(): while True: now_time = time.time() cluster_all_host_var = Gl.get_value('CLUSTER_ALL_HOSTS_VAR', []) cluster_status_var = Gl.get_value('CLUSTER_STATUS_VAR', {}) image_server_status_var = Gl.get_value('IMAGE_SERVER_STATUS_VAR', {}) all_image_server_host = Gl.get_value('ALL_IMAGE_SERVER_HOST_VAR', []) # if not cluster_all_host_var: # raise ValueError('Value error.CLUSTER_ALL_HOSTS_VAR is not allowed to be empty.') for host in cluster_all_host_var: if host not in cluster_status_var: cluster_status_var.update({host: {'status': False, 'time': 0}}) else: last_time = cluster_status_var.get(host).get('time') if now_time - last_time > HEARTBEAT_TIMEOUT_VAR: cluster_status_var.update({host: {'status': False, 'time': last_time}}) # if not all_image_server_host: # raise ValueError('Value error.ALL_IMAGE_SERVER_HOST_VAR is not allowed to be empty.') for host in all_image_server_host: if host not in image_server_status_var: image_server_status_var.update({host: {'status': False, 'time': 0}}) else: last_time = image_server_status_var.get(host).get('time') if now_time - last_time > HEARTBEAT_TIMEOUT_VAR: image_server_status_var.update({host: {'status': False, 'time': last_time}}) Gl.set_value('IMAGE_SERVER_STATUS_VAR', image_server_status_var) Gl.set_value('CLUSTER_STATUS_VAR', cluster_status_var) # _logger.write('检查结果:' + cluster_status_var.__str__(), level='info') time.sleep(2)
def start_heartbeats(): print '心跳服务运行中...' # +1防止两者皆为0 num_receivers = len(Gl.get_value('CLUSTER_ALL_HOSTS_VAR', [])) + len(Gl.get_value('ALL_IMAGE_SERVER_HOST_VAR', [])) + 1 receivers = [] for i in range(num_receivers): receiver = Receive(host=SERVICE_HOST_VAR, port=HEARTBEAT_PORT_VAR) receiver.setDaemon(True) receiver.start() receivers.append(receiver) try: Heartbeats.check_timeout() except KeyboardInterrupt: _logger.write('服务已停止', level='info') print 'Exited, OK'
def get_image_server_harbor(image_server): """ 获取harbor镜像列表 :param image_server: harbor镜像服务器地址 :return: """ image_server_status = Gl.get_value('IMAGE_SERVER_STATUS_VAR', {}) if image_server not in image_server_status or not image_server_status.get( image_server).get('status'): _logger.write('镜像服务器Host: \'' + str(image_server) + '\'无效或本Host不可用', level='warn') return {'message': 'image server unavailable', 'status': False} rq_url = _root_url.format(host=image_server, port=IMAGE_SERVER_PORT_VAR, root_path='image_harbor_server', type_path='') try: rq_obj = requests.get(rq_url) exec_result = json.loads(rq_obj.text) except ConnectionError: _logger.write(str(image_server) + '连接失败', 'warn') exec_result = { 'message': 'image server connect fail', 'status': False } return exec_result
def get_image_server_list(): """ 返回镜像服务器列表 :return:['image_server_host_1', 'image_server_host_2', ...] """ all_image_server_host_var = Gl.get_value('ALL_IMAGE_SERVER_HOST_VAR', []) return {'message': all_image_server_host_var, 'status': True}
def get_alive_image_server_list(): """ 返回可用的镜像服务器列表 :return: ['alive_image_server_host_1', 'alive_image_server_host_2', ...] """ info = [] all_image_server_host_var = Gl.get_value('ALL_IMAGE_SERVER_HOST_VAR', []) image_server_status = Gl.get_value('IMAGE_SERVER_STATUS_VAR', {}) for image_server in all_image_server_host_var: if image_server not in image_server_status or not image_server_status.get( image_server).get('status'): continue info.append(image_server) if info.__len__() > 0: return {'message': info, 'status': True} else: return {'message': info, 'status': False}
def get_image(host): """获取单个节点容器信息 由于每个Host仅可属于一个集群,故只需提供Host而无需提供集群ID :param host: 要查询的节点Host :return: { "message":[{ "message":{ 'id': 镜像id, 'short_id': 镜像短id, 'tags': 镜像标签列表, 'created': 镜像创建日期, 'size': 镜像大小, 'os': 镜像系统 } or err_reason, "status": bool.执行状态 },... ], "status": bool } """ cluster_status = Gl.get_value('CLUSTER_STATUS_VAR', {}) cluster_all_hosts = Gl.get_value('CLUSTER_ALL_HOSTS_VAR', []) if host not in cluster_all_hosts: _logger.write('节点Host: \'' + host + '\'无效', level='warn') return {'message': 'node unavailable', 'status': False} if host not in cluster_status or not cluster_status.get(host).get( 'status'): return {'message': 'node unavailable', 'status': False} rq_url = _root_url.format(host=host, port=SLAVE_SERVICE_PORT_VAR, root_path='image', type_path='_all') try: rq_obj = requests.get(rq_url) images_info = json.loads(rq_obj.text) except ConnectionError: _logger.write(str(host) + '连接失败', 'warn') return {'message': 'node connect fail', 'status': False} return images_info
def add_free_cluster(cluster_id): """标记集群为空闲 将指定集群标记为空闲 :param cluster_id: 集群ID :return: Boolean:标记执行状态 """ cluster_all_id = Gl.get_value('CLUSTER_ALL_ID_VAR', []) cluster_free_id = Gl.get_value('CLUSTER_FREE_ID_VAR', []) bool_status = True if cluster_id in cluster_free_id: _logger.write('集群标记失败: 该集群已空闲', level='warn') bool_status = False if cluster_id not in cluster_all_id: _logger.write('集群标记失败: 集群ID不存在', level='warn') bool_status = False if bool_status: cluster_free_id.append(cluster_id) Gl.set_value('CLUSTER_FREE_ID_VAR', cluster_free_id) return bool_status
def get_all_system(cluster_id, type_): """ 获取系统信息列表 构建url请求,向指定从节点发送获取系统信息列表请求 :param type_: 信息类型. 值类型为mem, disk, cpu :param cluster_id: 要获取的集群ID :return: [] or None """ system_info_list = {} _allow_type = ['mem', 'disk', 'cpu'] if type_ not in _allow_type: return {'message': 'type error', 'status': False} cluster_status = Gl.get_value('CLUSTER_STATUS_VAR', {}) cluster_all_id = Gl.get_value('CLUSTER_ALL_ID_VAR', []) cluster_all_info = Gl.get_value('CLUSTER_ALL_INFO_VAR', {}) if cluster_id not in cluster_all_id: _logger.write('集群ID: \'' + cluster_id + '\'未找到', 'warn') return {} for node in cluster_all_info.get(cluster_id).get('node'): node_host = node.get('host') if node_host not in cluster_status or not cluster_status.get( node_host).get('status'): continue rq_url = _root_url.format(host=node_host, port=SLAVE_SERVICE_PORT_VAR, root_path='system', type_path='') try: params = {'type': type_} rq_obj = requests.get(rq_url, params=params) rq_result = json.loads(rq_obj.text) except ConnectionError: _logger.write(str(node_host) + '连接失败', 'warn') rq_result = {'message': 'node connect error', 'status': False} system_info_list.update({node_host: rq_result}) return system_info_list
def operator_image(host, action_type, image_id_or_name, **kwargs): """ 操作镜像 包含镜像的删除, 查询, tag :param image_id_or_name: 镜像id或镜像名 .str :param action_type: 操作类型.允许值为remove, tag, search .str remove: 可附加变量为 force .bool(是否强制删除.默认值为False) search: tag: 可附加变量为 repository .str(表示镜像名); tag .str(表示版本,默认值None); force .bool(表示是否强制更改,默认值None) :param host: 节点ip :param kwargs: 以上可附加变量 :return: { "message":'ok' or err_reason, "status": .bool(执行状态) "url": .str(请求url,status 为True时显示) "refresh": .str(请求回执时间 ,status为True时显示) } """ _allow_action = ['remove', 'tag', 'search'] cluster_status = Gl.get_value('CLUSTER_STATUS_VAR', {}) if action_type not in _allow_action or host not in cluster_status or not cluster_status.get( host).get('status'): _logger.write('节点Host: \'' + host + '\'无效或本Host不可用', level='warn') return {'message': 'node unavailable', 'status': False} rq_url = _root_url.format(host=host, port=SLAVE_SERVICE_PORT_VAR, root_path='image', type_path='') if 'type' in kwargs or 'image_id_or_name' in kwargs: return {'message': 'type error', 'status': False} rq_args = {'type': action_type, 'image_id_or_name': image_id_or_name} rq_args.update(kwargs) try: rq_obj = requests.post(rq_url, json=rq_args) exec_result = json.loads(rq_obj.text) return exec_result except ConnectionError: _logger.write(str(host) + '连接失败', 'warn') return {'message': 'connect fail', 'status': False}
def create_container_shell(host, cmd): """ 创建容器 创建容器的命令行模式, 通过shell语句创建 eg: docker create *** :param host: 执行节点 :param cmd: :return: { "message": , error_reason or container_id "status": , 'url': , 'refresh': } """ cluster_status = Gl.get_value('CLUSTER_STATUS_VAR', {}) if host not in cluster_status or not cluster_status.get(host).get( 'status'): _logger.write('节点Host: \'' + host + '\'无效或本Host不可用', level='warn') return {'message': 'host unavailable', 'status': False} pattern_cmd = '^docker\s+(run|create)\s+.*' if re.match(pattern_cmd, cmd) is None: _logger.write('执行出错: 命令不合法', level='warn') return {'message': 'illegal command', 'status': False} rq_url = _root_url.format(host=host, port=SLAVE_SERVICE_PORT_VAR, root_path='container', type_path='') rq_args = {'type': 'create_shell', 'shell_cmd': cmd} try: rq_obj = requests.post(rq_url, json=rq_args) exec_result = json.loads(rq_obj.text) return exec_result except ConnectionError: _logger.write(str(host) + '连接失败', 'warn') return {'message': 'host connect fail', 'status': False}
def run(self): self.sock.bind((self.host, self.port)) _logger.write('心跳检测服务已启动', level='info') try: while True: key, address = self.sock.recvfrom(1024) receive_time = time.time() host = address[0] # 集群所有从节点IP列表 cluster_all_host_var = Gl.get_value('CLUSTER_ALL_HOSTS_VAR', []) # 集群所有镜像服务器列表 all_image_server_host_var = Gl.get_value('ALL_IMAGE_SERVER_HOST_VAR', []) # 集群从节点信息列表 cluster_all_info_var = Gl.get_value('CLUSTER_ALL_INFO_VAR', {}) # 集群镜像服务器信息列表 all_image_server_info_var = Gl.get_value('ALL_IMAGE_SERVER_INFO_VAR', {}) # 从节点状态字典 cluster_status_var = Gl.get_value('CLUSTER_STATUS_VAR', {}) # 镜像服务器字典 image_server_status_var = Gl.get_value('IMAGE_SERVER_STATUS_VAR', {}) # 集群ID列表 cluster_all_id = Gl.get_value('CLUSTER_ALL_ID_VAR', []) # 集群空闲ID列表 cluster_free_id = Gl.get_value('CLUSTER_FREE_ID_VAR', []) try: type_, hostname, cluster_id_or_registry_server_port = key.split('%')[0].split('|') print hostname hostname += '({host_end})'.format(host_end=host.split('.')[-1]) except ValueError: continue # 检查节点类型 if type_ != 'slave' and type_ != 'image': continue # 检查密钥是否正确 if not self._check_key(key): continue if type_ == 'slave': # 如果是新加入的机器 if host not in cluster_all_host_var: # 修改集群配置相关项目 cluster_all_host_var.append(host) if cluster_id_or_registry_server_port in cluster_all_info_var: if 'node' in cluster_all_info_var[cluster_id_or_registry_server_port]: cluster_all_info_var[cluster_id_or_registry_server_port]['node'].append({ 'name': hostname, 'host': host }) else: cluster_all_info_var[cluster_id_or_registry_server_port].update({ 'node': [{ 'name': hostname, 'host': host }] }) else: cluster_all_info_var.update({ cluster_id_or_registry_server_port: {'node': [{'name': hostname, 'host': host}]} }) cluster_all_id.append(cluster_id_or_registry_server_port) cluster_free_id.append(cluster_id_or_registry_server_port) # 修改节点状态 if host in cluster_status_var: cluster_status_var[host].update({'time': receive_time, 'status': True}) else: cluster_status_var.update({host: {'status': True, 'time': receive_time}}) elif type_ == 'image': # 若为新加入的镜像服务器, 修改相关信息 if host not in all_image_server_host_var: all_image_server_host_var.append(host) all_image_server_info_var.update({host: {'registry_port': cluster_id_or_registry_server_port}}) # 修改节点状态 if host in image_server_status_var: image_server_status_var[host].update({'time': receive_time, 'status': True}) else: image_server_status_var.update({host: {'status': True, 'time': receive_time}}) else: pass # 写入数据 Gl.set_value('CLUSTER_STATUS_VAR', cluster_status_var) Gl.set_value('IMAGE_SERVER_STATUS_VAR', image_server_status_var) Gl.set_value('CLUSTER_ALL_HOSTS_VAR', cluster_all_host_var) Gl.set_value('ALL_IMAGE_SERVER_HOST_VAR', all_image_server_host_var) Gl.set_value('CLUSTER_ALL_INFO_VAR', cluster_all_info_var) Gl.set_value('CLUSTER_FREE_ID_VAR', cluster_free_id) Gl.set_value('CLUSTER_ALL_ID_VAR', cluster_all_id) Gl.set_value('ALL_IMAGE_SERVER_INFO_VAR', all_image_server_info_var) finally: self.sock.close()
#!coding: utf-8 """ 本程序用于启动主服务的后台部分,包含解析文件服务,心跳服务 """ import threading from manager.response import start_web_server from manager.heartbeat import start_heartbeats from manager.tools import GlobalMap as Gl # -------------------清理变量---------------- # Gl.clean() print '变量初始化完成' # -------------------后台响应服务-------------# thread = threading.Thread(target=start_web_server) thread.setDaemon(True) thread.start() print '启动后台响应服务' # ------------------------------------------# # -------------------心跳服务---------------- # start_heartbeats() # ------------------------------------------ #
def operator_container(host, action_type, container_id_or_name, **kwargs): """ 操作容器 包含容器的启动,停止,重命名,构建,log,重启等操作 :param host: 节点ip :param container_id_or_name: .str :param action_type: 操作类型,值可以为 .str kill: 可附带参数 signal, .str(信号.默认值为None) start: stop: 可附带单数为 timeout, .int(默认值为10) restart: 可附带单数为 timeout, .int(默认值为10) rename: 必须附带参数 new_name .str(新的镜像名) pause: logs: 可附带参数为 stderr .bool(标准错误流.默认True); stdout .bool(标准输出流.默认True); timestamps .bool(是否输出时间.默认True) commit: 可选附带参数为 repository .str; tag .str; changes: .str; author: .str; message: .str remove: 可选附带参数为 v: .bool(是否删除数据卷 ) link: .bool(是否删除连接容器) force: .bool(是否强制删除) unpause: start: :param kwargs 以上所列附带参数 :return: { "message": , #请求结果.str "status": , #执行状态.bool "url": , #请求url.str "refresh": #请求回执时间.str } or { "message": error_reason,.str "status": False.bool } """ _allow_action = [ 'start', 'stop', 'restart', 'rename', 'logs', 'pause', 'commit', 'kill', 'remove', 'unpause' ] cluster_status = Gl.get_value('CLUSTER_STATUS_VAR', {}) if action_type not in _allow_action or host not in cluster_status or not cluster_status.get( host).get('status'): _logger.write('节点Host: \'' + str(host) + '\'无效或本Host不可用', level='warn') return {'message': 'host unavailable', 'status': False} rq_url = _root_url.format(host=host, port=SLAVE_SERVICE_PORT_VAR, root_path='container', type_path='') if 'type' in kwargs or 'container_id_or_name' in kwargs: return {'message': 'type error', 'status': False} rq_args = { 'type': action_type, 'container_id_or_name': container_id_or_name } rq_args.update(kwargs) try: rq_obj = requests.post(rq_url, json=rq_args) exec_result = json.loads(rq_obj.text) return exec_result except ConnectionError: _logger.write(str(host) + '连接失败', 'warn') return {'message': 'host connect fail', 'status': False}
def get_all_containers(cluster_id): """获取容器列表,获取所有容器列表 构建url请求,向指定从节点发送获取容器列表请求 :param cluster_id: 要获取的集群ID :return: { "host1" : { "status": , "refresh": ,请求回执, status为True时才可显示 "url": , 请求url, status为True时才可显示 "message": [ { message: { 'id': 容器id, 'short_id': 容器短id, 'status': 容器状态, 'running': 容器是否在运行, 'finishedAt': 容器退出时间, 'startedAt': 容器开始时间, 'created': 容器创建日期 'image': 容器依赖镜像, 'exit_time': 容器退出时间. }, 'status': bool },... ] }, "host2": { ... }, ... } or (部分节点无效时) { "host1": { "status": , "message": error_reason }, "host2": { ... } } or (集群不可用或未找到) {} """ containers_dict = {} cluster_status = Gl.get_value('CLUSTER_STATUS_VAR', {}) cluster_all_id = Gl.get_value('CLUSTER_ALL_ID_VAR', []) cluster_all_info = Gl.get_value('CLUSTER_ALL_INFO_VAR', {}) if cluster_id not in cluster_all_id: _logger.write('集群ID: \'' + cluster_id + '\'未找到', 'warn') return {} for node in cluster_all_info.get(cluster_id).get('node'): node_host = node.get('host') if node_host not in cluster_status or not cluster_status.get( node_host).get('status'): continue rq_url = _root_url.format(host=node_host, port=SLAVE_SERVICE_PORT_VAR, root_path='container', type_path='_all') try: rq_obj = requests.get(rq_url) rq_result = json.loads(rq_obj.text) except ConnectionError: _logger.write(str(node_host) + '连接失败', 'warn') rq_result = { 'message': str(node_host) + ' connect fail', 'status': False } containers_dict.update({node_host: rq_result}) return containers_dict
def get_all_images(cluster_id): """ :param cluster_id: 集群ID :return: { "host1" : { "status": , "refresh": , "url": , "message": [ { "message":{ 'id': 镜像id, 'short_id': 镜像短id, 'tags': 镜像标签列表, 'created': 镜像创建日期, 'size': 镜像大小, 'os': 镜像系统 } or err_reason, },... ] }, "host2": { ... }, ... } or { "host1": { "status":, "message": error_reason, }, "host2": { "status":, "message": error_reason }, ... } or { } """ images_dict = {} cluster_status = Gl.get_value('CLUSTER_STATUS_VAR', {}) cluster_all_id = Gl.get_value('CLUSTER_ALL_ID_VAR', []) cluster_all_info = Gl.get_value('CLUSTER_ALL_INFO_VAR', {}) if cluster_id not in cluster_all_id: _logger.write('集群ID: \'' + cluster_id + '\'未找到', 'warn') return {'message': 'node unavailable', 'status': False} for node in cluster_all_info.get(cluster_id).get('node'): node_host = node.get('host') if node_host not in cluster_status or not cluster_status.get( node_host).get('status'): continue rq_url = _root_url.format(host=node_host, port=SLAVE_SERVICE_PORT_VAR, root_path='image', type_path='_all') try: rq_obj = requests.get(rq_url) rq_result = json.loads(rq_obj.text) except ConnectionError: _logger.write(str(node_host) + '连接失败', 'warn') rq_result = {'message': 'node connect fail', 'status': False} images_dict.update({node_host: rq_result}) return images_dict
def download_image(download_to_host, image_server_host, repository): """ 下载镜像 从远程镜像仓库下载镜像 :param image_server_host: 镜像服务器ip :param download_to_host: 要下载镜像的节点 :param repository: 所要下载的镜像名,包含镜像tag :return: { "message": , "status": , "refresh": , "url": } or { "message": , "status": } """ cluster_status = Gl.get_value('CLUSTER_STATUS_VAR', {}) image_server_status = Gl.get_value('IMAGE_SERVER_STATUS_VAR', {}) all_image_server_info_var = Gl.get_value('ALL_IMAGE_SERVER_INFO_VAR', {}) if download_to_host not in cluster_status or not cluster_status.get( download_to_host).get('status'): _logger.write('节点Host: \'' + str(download_to_host) + '\'无效或本Host不可用', level='warn') return {'message': 'node unavailable', 'status': False} if image_server_host not in image_server_status or not image_server_status.get( image_server_host).get('status'): _logger.write('镜像服务器Host: \'' + str(image_server_host) + '\'无效或本Host不可用', level='warn') return {'message': 'image server unavailable', 'status': False} registry_server_port = all_image_server_info_var.get( image_server_host).get('registry_port') # 提取tag try: repository_tag = repository.split(':')[1] except IndexError: repository_tag = None # 拼接仓库名 repository = image_server_host + ':' + str( registry_server_port) + '/' + repository.split(':')[0] print repository rq_url = _root_url.format(host=download_to_host, port=SLAVE_SERVICE_PORT_VAR, root_path='image', type_path='') rq_args = { 'repository': repository, 'tag': repository_tag, 'type': 'pull' } try: rq_obj = requests.post(rq_url, json=rq_args) exec_result = json.loads(rq_obj.text) except ConnectionError: _logger.write(str(download_to_host) + '连接失败', 'warn') exec_result = {'message': 'host connect fail', 'status': False} return exec_result