容易的linux自动化运维工具之clinet端(二)
2019独角兽企业重金招聘Python工程师标准>>>
原文:https://www.3qos.com/article/101.html
作者:容易 日期:2015-03-17
备注:非本人同意,请勿转载
接上一篇 容易的linux集中管理工具之master端(一)
client端代码
#-*- coding: UTF-8 -*- __author__ = 'tiger'#!/usr/bin/env pythonimport zmq, time, sys, os, atexitfrom signal import SIGTERMimport randomimport logging#import ConfigParserimport subprocessfrom logging.handlers import RotatingFileHandlerimport socketimport fcntlimport structimport signal#定义日志函数def mylog(logfile):rthandler = RotatingFileHandler(logfile, 'a', maxBytes=50 * 1024 * 1024, backupCount=3)formatter = logging.Formatter('%(levelname)s %(thread)d %(threadName)s %(process)d %(funcName)s %(asctime)s %(filename)s[line:%(lineno)d] %(message)s',datefmt='%a, %d %b %Y %H:%M:%S')rthandler.setFormatter(formatter)log = logging.getLogger()log.setLevel(logging.INFO)log.addHandler(rthandler)return log#获取指定接口的IP地址def get_ip_address(ifname):s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)return socket.inet_ntoa(fcntl.ioctl(s.fileno(),0x8915, # SIOCGIFADDRstruct.pack('256s', ifname[:15]))[20:24])#定义命令或者脚本执行超时所触发的错误class ProcessTimeout(Exception):pass#定义命令或者脚本执行超时所触发的错误句柄def timeout_handler(signum, frame):raise ProcessTimeout#执行命令的函数def exec_shell(task, rundir=None, timeout=None):#定义超时if timeout:signal.signal(signal.SIGALRM, timeout_handler)signal.alarm(timeout)p = subprocess.Popen(task, bufsize=0, shell=True, cwd=rundir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)try:stdout, stderr = p.communicate()returncode = p.poll()signal.alarm(0)except ProcessTimeout:p.stdout.close()p.stderr.close()p.terminate()stderr = 'Calculation was taking too long, so I killed it dead.\n'returncode = 'timeout'del p#返回的信息,如果成功返回标准输出#错误返回标准错误if returncode == 0:return [returncode, stdout]else:return [returncode, stderr]#任务类别为脚本时调用该函数def exec_script(fileserver, script, dirpath, rundir=None, timeout=None):fileurl = fileserver + script['script_name']#去http服务器下载脚本,直接调用系统的wget命令下载getfile = 'wget -N -P ' + dirpath + ' ' + fileurlfilename = dirpath + script['script_name']task = script['script_env'] + ' ' + filenamegetfile_res = exec_shell(getfile, rundir=rundir, timeout=timeout)if getfile_res[0] == 0:task_res = exec_shell(task, rundir=rundir, timeout=timeout)try:os.remove(filename)except Exception, err:task_res[1] = task_res[1] + str(err)return task_reselse:return getfile_res#与master建立连接完成与master的通信def ioloop(sock_file, homedir, mip, stdout):#定义运行目录,默认情况下,脚或者命令在该目录执行dirpath = homedir + '/run/'#定义日常函数log = mylog(stdout)context = zmq.Context()socket = context.socket(zmq.REQ)socket.setsockopt(zmq.LINGER, 0)socket.connect(sock_file)poller = zmq.Poller()poller.register(socket, zmq.POLLIN)#循环while 1:#发送请求信息try:socket.send_pyobj({'req_type': 'task', 'ip': mip})except Exception, err:log.warn(str(err))socket.close()context.term()time.sleep(random.randint(1, 5))context = zmq.Context()socket = context.socket(zmq.REQ)socket.setsockopt(zmq.LINGER, 0)socket.connect(sock_file)poller = zmq.Poller()poller.register(socket, zmq.POLLIN)continue#服务端响应超时if poller.poll(20 * 1000):rep = socket.recv_pyobj()#如果有响应信息,判断响应的类别。try:rep_type = rep['rep_type']except Exception, err:log.info(str(err))time.sleep(random.uniform(0.8, 1.2))continue#如果响应类别为newtask,则获取本次任务所需的其他信息if rep_type == 'newtask':try:job_id = rep['id']job_task = rep['task']job_type = rep['type']cmd_timeout = rep['cmdtimeout']rundir = rep['rundir']log.warn('start new job ' + str(rep))except Exception, err:if job_id:socket.send_pyobj({'id': job_id, 'code': '99', 'info': str(err), 'ip': mip, 'req_type': 'report'})socket.recv_pyobj()time.sleep(random.uniform(0.8, 1.2))log.warn(str(err) + str(rep))continue#如果任务类别是脚本,则尝试获取执行脚本所需的其他信息if job_type == 's':try:script_env = rep['env']script = {'script_name': job_task, 'script_env': script_env}fileserver = rep['fileserver']#调用运行脚本的函数执行脚本if rundir == 'None':res = exec_script(fileserver, script, dirpath, rundir=dirpath, timeout=cmd_timeout)else:res = exec_script(fileserver, script, dirpath, rundir=rundir, timeout=cmd_timeout)except Exception, err:log.warn(str(err))continue#任务类别为其他时则统一当作命令执行else:if rundir == 'None':res = exec_shell(job_task, rundir=dirpath, timeout=cmd_timeout)else:res = exec_shell(job_task, rundir=rundir, timeout=cmd_timeout)#将执行结果返回给master,标记请求类别为report,然master知道该请求是任务报告请求。socket.send_pyobj({'id': job_id, 'code': res[0], 'info': res[1], 'ip': mip, 'req_type': 'report'})socket.recv_pyobj()log.info(str({'id': job_id, 'code': res[0], 'info': res[1], 'ip': mip}))time.sleep(random.uniform(0.8, 1.2))else:time.sleep(random.uniform(0.8, 1.2))else:#响应超时时尝试重连master端log.warn("master server connect time out,will colse current socket,try again.")socket.close()context.term()time.sleep(random.randint(1, 5))context = zmq.Context()socket = context.socket(zmq.REQ)socket.setsockopt(zmq.LINGER, 0)socket.connect(sock_file)poller = zmq.Poller()poller.register(socket, zmq.POLLIN)socket.close()context.term()def ip_check(ip):q = ip.split('.')return len(q) == 4 and len(filter(lambda x: x >= 0 and x <= 255, \map(int, filter(lambda x: x.isdigit(), q)))) == 4class Daemon:def __init__(self, pidfile, sock_file, homedir, mip, stdin='/dev/null', stdout='/dev/null',stderr='/dev/null'):self.stdin = stdinself.stdout = stdoutself.stderr = stderrself.pidfile = pidfileself.homedir = homedirself.sock_file = sock_fileself.mip = mipdef _daemonize(self):#脱离父进程try:pid = os.fork()if pid > 0:sys.exit(0)except OSError, e:sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))sys.exit(1)#脱离终端os.setsid()#修改当前工作目录os.chdir("/")#重设文件创建权限os.umask(0)#第二次fork,禁止进程重新打开控制终端try:pid = os.fork()if pid > 0:sys.exit(0)except OSError, e:sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))sys.exit(1)sys.stdout.flush()sys.stderr.flush()si = file(self.stdin, 'r')so = file(self.stdout, 'a+')se = file(self.stderr, 'a+', 0)#重定向标准输入/输出/错误os.dup2(si.fileno(), sys.stdin.fileno())os.dup2(so.fileno(), sys.stdout.fileno())os.dup2(se.fileno(), sys.stderr.fileno())#注册程序退出时的函数,即删掉pid文件atexit.register(self.delpid)pid = str(os.getpid())file(self.pidfile, 'w+').write("%s\n" % pid)def delpid(self):os.remove(self.pidfile)def start(self):# Check for a pidfile to see if the daemon already runstry:pf = file(self.pidfile, 'r')pid = int(pf.read().strip())pf.close()except IOError:pid = Noneif pid:message = "pidfile %s already exist. Daemon already running?\n"sys.stderr.write(message % self.pidfile)sys.exit(1)# Start the daemonself._daemonize()self._run()def stop(self):# Get the pid from the pidfiletry:pf = file(self.pidfile, 'r')pid = int(pf.read().strip())pf.close()except IOError:pid = Noneif not pid:message = "pidfile %s does not exist. Daemon not running?\n"sys.stderr.write(message % self.pidfile)return # not an error in a restart# Try killing the daemon processtry:while 1:os.kill(pid, SIGTERM)time.sleep(0.1)except OSError, err:err = str(err)if err.find("No such process") > 0:if os.path.exists(self.pidfile):os.remove(self.pidfile)else:print str(err)sys.exit(1)def restart(self):self.stop()self.start()def _run(self):pass#重写Daemon的_run函数实现自己的Daemon进程class MyDaemon(Daemon):def _run(self, ):ioloop(self.sock_file, self.homedir, self.mip, self.stdout)#定义主函数,创建相关运行目录和定义日志路径等def main():homedir = os.getcwd()for i in ('log', 'run'):path = homedir + '/' + iif not os.path.exists(path):os.makedirs(path, 0755)stdout = homedir + '/log' + '/oaos_client.log'stderr = homedir + '/log' + '/oaos_client.err'pidfile = homedir + '/run' + '/oaos_client.pid'#master的tcp接口sock_file = "tcp://192.168.4.194:7777"#该接口是指用来与master通信的客户端IP接口ifname = 'eth0'try:mip = get_ip_address(ifname)except Exception, err:print errsys.exit(3)daemon = MyDaemon(pidfile, sock_file, homedir, mip, stdout=stdout, stderr=stderr)if len(sys.argv) == 2:if 'start' == sys.argv[1]:daemon.start()elif 'stop' == sys.argv[1]:daemon.stop()elif 'restart' == sys.argv[1]:daemon.restart()else:print "Unknown command"sys.exit(2)sys.exit(0)else:print "usage: %s start|stop|restart" % sys.argv[0]sys.exit(2)if __name__ == "__main__":main()
转载于:https://my.oschina.net/u/245398/blog/389976
容易的linux自动化运维工具之clinet端(二)相关推荐
- Linux 自动化运维工具 ansible
文章目录 1.简介 2.安装 3.常用命令选项说明 4.使用 4.1.执行远程命令 4.2.执行远程脚本 4.3.分发文件到远程服务器 4.3.1.复制单个文件 4.3.2.复制压缩文件到远程并解压 ...
- Linux自动化运维工具ansible详解
文章目录 认识ansible ansible的组成 ansible的相关文件 ansible的使用 ansible的常用模块 1.copy模块 2.fetch模块 3.command模块 4.shel ...
- Linux自动化运维工具 老男孩Linux云计算培训
Linux运维人员必会开源运维工具体系 说明:不同的技术人员,在不同的阶段确定知识边界非常重要,否则,虽然是千里马,但是不知道终点在哪,最终累死也达不到目标. 例如:拿8K要学多少知识,拿15K又要学 ...
- 自动化运维工具——ansible安装及模块介绍
ansbile 前言 一.主流自动化运维工具简介 1.1 Puppet 1.2 Saltstack 1.3 Ansible 二.Ansible 运维工具原理 三.Ansible安装 3.1 下载软件包 ...
- 常见的自动化运维工具介绍及特点、安装ansible
常见的自动化运维工具介绍及特点.安装ansible 一.什么是自动化运维? 简单来说,自动化运维就是将日常重复性工作按照事先设定好的规则,在一定时间范围内自动化运行,而不需要人为参与. 将周期性.重复 ...
- linux自动化运维ansible
linux自动化运维ansible 一.概述 二.安装 1.配置安装源 2.安装 3.查询版本信息 三.设置主机清单 1.添加ip及账号信息 2.修改主配置文件 3.测试是否成功 四.模块应用 1.模 ...
- 自动化运维工具Ansible
ansible简介: ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了批量系统配置.批 ...
- mysql 自动化运维工具_MySQL使用工具Inception实现自动化运维
MySQL使用工具Inception实现自动化运维 发布时间:2020-05-27 17:11:14 来源:51CTO 阅读:180 作者:三月 下面一起来了解下MySQL使用工具Inception实 ...
- mysql 自动化运维工具_部署MySQL自动化运维工具inception+archer
*************************************************************************** 部署MySQL自动化运维工具inception+ ...
最新文章
- 软件开发的N种基础武器 - 最新清单
- 信息系统项目管理师案例考试汇总(2005~2021年)
- leetcode39. 组合总和
- LeetCode 127. 单词接龙(图的BFS/双向BFS)
- POJ3420 Quad Tiling(模板+矩阵快速幂)
- 前端开发利器—FIDDLER 转
- cURL 原作者收到死亡恐吓邮件!
- JavaScript 虚拟键盘 A-Keyboard
- WPS中如何启用宏,附wps.vba.exe下载链接(百度云盘,永久有效)
- 直通车怎么能不推广计算机设备,直通车智能推广具体怎么设置?如何操作?
- vscode能写winform窗体吗_VSCode——愉快的写C#
- 论文解读:《基于注意力的多标签神经网络用于12种广泛存在的RNA修饰的综合预测和解释》
- Win10 21H2 19044+vs2019 WDK驱动开发,错误 MSB8040缓解Spectre 漏洞的库以及输出SXS.DLL的垃圾信息
- 前端市场又“饱和”了,还有必要学吗?
- 利用MCI命令进行 播放录制音乐,以及弹出光驱,音量控制获得播放进度等等操作。。。开发必备。
- 华兴数控g71外圆循环编程_华兴数控G71指令怎么编
- 快速制作U盘启动盘和U盘安装盘的方法
- marker 头像 高德地图_手机地图导航软件高德地图1.如何下载高德地图
- Leetcode——安卓系统手势解锁(九宫格)
- 相继上一篇,thingsboard的二次开发环境配置和简单的logo替换
热门文章
- json.dumps直接保存中文而非字符集的方法
- Notebook中?的trick
- F1 score的意义
- linux误修改文件名恢复,如何在 Linux 中找出最近或今天被修改的文件-linux修改文件名...
- linux lib64被改名,问题解决:Centos误将/lib64更改为lib64.bak
- 第11章:项目风险管理(2)—章节重点
- java制作文本框中的表格输入List数据
- Hexo+腾讯CVM+又拍云+github+gitee+coding
- 笔记-项目沟通管理-如何改进项目沟通
- Geoserver在Linux上的安装(图文教程)