【实战小项目】python开发自动化运维工具--批量操作主机
有很多开源自动化运维工具都很好用如ansible/salt stack等,完全不用重复造轮子。只不过,很多运维同学学习Python之后,苦于没小项目训练,本篇演示用Python写一个批量操作主机的工具,大家空余时候可以试着写写,完善完善。
1 思路分析
在运维工作中,古老的方式部署环境、上线代码可能都需要手动在服务器上敲命令,不胜其烦。所以,脚本,自动化工具等还是很有必要的。我觉得一个批量操作工具应该考虑以下几点:
(1)本质上,就是到远程主机上执行命令并返回结果。
(2)做到批量。也就是要并发对多台机器进行操作。
(3)将返回的结果,清晰地展示给用户。
通常开源的主机批量管理工具有两类,一类是有agent,如SaltStack、Puppet等;另一类是无agent如ansible。虽然我们没必要重复造轮子,但是可以试着写一写,一是加深对这类软件原理的理解,二是练习Python。建议如果服务器规模在1000台以内的用无agent的方式也能hold住;如果超过1000台,用有agent的会好太多。
接下来我们一起看看怎么具体实现。
2 到远程机器上执行命令
到远程机器上执行命令,并返回结果,至少有两种方式:一是用paramiko模块;而是可以建立机器互信,从中控执行ssh命令。
下面我把自己封装好的代码贴一下,是基于paramiko模块封装的,ssh的大家可以自己实现:
import paramiko
class SSHParamiko(object):
err = "argument passwd or rsafile can not be None"
def __init__(self, host, port, user, passwd=None, rsafile=None):
self.h = host
self.p = port
self.u = user
self.w = passwd
self.rsa = rsafile
def _connect(self):
if self.w:
return self.pwd_connect()
elif self.rsa:
return self.rsa_connect()
else:
raise ConnectionError(self.err)
def _transfer(self):
if self.w:
return self.pwd_transfer()
elif self.rsa:
return self.rsa_transfer()
else:
raise ConnectionError(self.err)
def pwd_connect(self):
conn = paramiko.SSHClient()
conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
conn.connect(self.h, self.p, self.u, self.w)
return conn
def rsa_connect(self):
pkey = paramiko.RSAKey.from_private_key_file(self.rsa)
conn = paramiko.SSHClient()
conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
conn.connect(hostname=self.h, port=self.p, username=self.u, pkey=pkey)
return conn
def pwd_transfer(self):
transport = paramiko.Transport(self.h, self.p)
transport.connect(username=self.u, password=self.w)
sftp = paramiko.SFTPClient.from_transport(transport)
return sftp, transport
def rsa_transfer(self):
pkey = paramiko.RSAKey.from_private_key_file(self.rsa)
transport = paramiko.Transport(self.h, self.p)
transport.connect(username=self.u, pkey=pkey)
sftp = paramiko.SFTPClient.from_transport(transport)
return sftp, transport
def run_cmd(self, cmd):
conn = self._connect()
stdin, stdout, stderr = conn.exec_command(cmd)
code = stdout.channel.recv_exit_status()
stdout, stderr = stdout.read(), stderr.read()
conn.close()
if not stderr:
return code, stdout.decode()
else:
return code, stderr.decode()
def get_file(self, remote, local):
sftp, conn = self._transfer()
sftp.get(remote, local)
conn.close()
def put_file(self, local, remote):
sftp, conn = self._transfer()
sftp.put(local, remote)
conn.close()
当然,代码还可以重构一下哈。接下来我们看下效果:
if __name__ == '__main__':
h = "我的测试机IP"
p = 22
u = "我的用户名"
w = "我的密码" obj = SSHParamiko(h, p, u, w)
r = obj.run_cmd("df -h")
print(r[0])
print(r[1])
执行之后的结果是:
0
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 40G 3.4G 34G 9% /
devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs 3.9G 410M 3.5G 11% /run
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
/dev/vdb 300G 12G 289G 4% /search/odin
tmpfs 783M 0 783M 0% /run/user/0
tmpfs 783M 0 783M 0% /run/user/1000
可以清晰看到第一行是命令执行的状态码,0表示成功,非0表示失败;第二行开始就是我们的命令返回结果。是不是比较清晰呢?
3 并发执行并展示输出结果
并发执行通常用Python3自带的线程模块就行,这里我用的from concurrent.futures import ThreadPoolExecutor。并且当拿到结果之后,我还做了一些格式化输出,比如绿色输出表示成功,红色输出表示命令执行失败,黄色表示提醒等。废话不多说,直接看代码吧!
from concurrent.futures import ThreadPoolExecutor class AllRun(object):
def __init__(self, ssh_objs, cmds, max_worker=50):
self.objs = [o for o in ssh_objs]
self.cmds = [c for c in cmds]
self.max_worker = max_worker # 最大并发线程数 self.success_hosts = [] # 存放成功机器数目
self.failed_hosts = [] # 存放失败的机器IP
self.mode = None
self.func = None def serial_exec(self, obj):
"""单台机器上串行执行命令,并返回结果至字典"""
result = list()
for c in self.cmds:
r = obj.run_cmd(c)
result.append([c, r])
return obj, result def concurrent_run(self):
"""并发执行"""
future = ThreadPoolExecutor(self.max_worker)
for obj in self.objs:
try:
future.submit(self.serial_exec, obj).add_done_callback(self.callback)
except Exception as err:
err = self.color_str(err, "red")
print(err)
future.shutdown(wait=True) def callback(self, future_obj):
"""回调函数,处理返回结果"""
ssh_obj, rlist = future_obj.result()
print(self.color_str("{} execute detail:".format(ssh_obj.h), "yellow"))
is_success = True
for item in rlist:
cmd, [code, res] = item
info = f"{cmd} | code => {code}\nResult:\n{res}"
if code != 0:
info = self.color_str(info, "red")
is_success = False
if ssh_obj.h not in self.failed_hosts:
self.failed_hosts.append(ssh_obj.h)
else:
info = self.color_str(info, "green")
print(info)
if is_success:
self.success_hosts.append(ssh_obj.h)
if ssh_obj.h in self.failed_hosts:
self.failed_hosts.remove(ssh_obj.h) def overview(self):
"""展示总的执行结果"""
for i in self.success_hosts:
print(self.color_str(i, "green"))
print("-" * 30)
for j in self.failed_hosts:
print(self.color_str(j, "red"))
info = "Success hosts {}; Failed hosts {}."
s, f = len(self.success_hosts), len(self.failed_hosts)
info = self.color_str(info.format(s, f), "yellow")
print(info) @staticmethod
def color_str(old, color=None):
"""给字符串添加颜色"""
if color == "red":
new = "\033[31;1m{}\033[0m".format(old)
elif color == "yellow":
new = "\033[33;1m{}\033[0m".format(old)
elif color == "blue":
new = "\033[34;1m{}\033[0m".format(old)
elif color == "green":
new = "\033[36;1m{}\033[0m".format(old)
else:
new = old
return new if __name__ == '__main__':
h1 = "adime01.shouji.sjs.ted"
p1 = 22
u1 = "odin"
w1 = "*****" h = "10.129.206.97"
p = 22
u = "root"
w = "*****" obj1 = SSHParamiko(h1, p1, u1, w1)
obj = SSHParamiko(h, p, u, w) cmds = ["df -h", "ls"] all_obj = AllRun([obj1, obj], cmds)
all_obj.concurrent_run()
all_obj.overview()
上述代码运行的结果:

从执行结果来看,高亮显示,清新明了。既显示了各个主机的各个命令执行状态码,返回结果,最后还汇总结果,成功了多少台机器和失败了多少台机器。
我们还可以换一下执行的命令,让命令执行失败看看:

后期还可以包装一下,将主机、密码、批量执行的命令写在配置文件中;或再根据需要包装成命令行工具,在日常运维工作中可以适当减少人肉敲命令的繁琐。
【实战小项目】python开发自动化运维工具--批量操作主机的更多相关文章
- 项目实战10.1—企业级自动化运维工具应用实战-ansible
实战环境: 公司计划在年底做一次大型市场促销活动,全面冲刺下交易额,为明年的上市做准备.公司要求各业务组对年底大促做准备,运维部要求所有业务容量进行三倍的扩容,并搭建出多套环境可以共开发和测试人员做测 ...
- 企业级自动化运维工具应用实战ansible
公司计划在年底做一次大型市场促销活动,全面冲刺下交易额,为明年的上市做准备.公司要求各业务组对年底大促做准备,运维部要求所有业务容量进行三倍的扩容,并搭建出多套环境可以共开发和测试人员做测试,运维老大 ...
- 企业级自动化运维工具应用实战-ansible
背景 公司计划在年底做一次大型市场促销活动,全面冲刺下交易额,为明年的上市做准备.公司要求各业务组对年底大促做准备,运维部要求所有业务容量进行三倍的扩容,并搭建出多套环境可以共开发和测试人员做测试,运 ...
- Linux实战教学笔记25:自动化运维工具之ansible (一)
第二十五节 ansible之文件的批量分发 标签(空格分隔): Linux实战教学笔记-陈思齐 ---本教学笔记是本人学习和工作生涯中的摘记整理而成,此为初稿(尚有诸多不完善之处),为原创作品,允许转 ...
- 企业级LINUX自动化运维工具Ansible实战课程下载
什么是Ansible? Ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.chef.func.fabric)的优点,实现了批量系统配置.批量程序部署.批量 ...
- CentOS7Linux中自动化运维工具Ansible的安装,以及通过模块批量管理多台主机
使用自动化运维工具Ansible集中化管理服务器 Ansible概述 Ansible是一款为类Unix系统开发的自由开源的配置和自动化工具.它用Python写成,类似于saltstack和Puppet ...
- 自动化运维工具 SaltStack 搭建
原文地址:https://www.ibm.com/developerworks/cn/opensource/os-devops-saltstack-in-cloud/index.html#N10072 ...
- Ansible 自动化运维工具
Ansible 自动化运维工具 Ansible是什么? Ansible是一个"配置管理工具"也是一个"自动化运维工具" Ansible 作用: Ansible是 ...
- Linux轻量级自动化运维工具— Ansible
Ansible 是什么 ? ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了批量系统配 ...
随机推荐
- eclipse中tomcat内存溢出设置
Eclipse里启动Tomcat,配置内存大小 2009年12月11日 星期五 10:50 一般安装完eclipse之后,在安装目录下你应该可以看到有一个 eclipse.ini 文件,对了,就是在这 ...
- windows SSH Tunnel实施日记
1.准备条件:SSH跳板服务器一个.软件:Putty,CCProxy 2.putty建立SSH Tunnel:先在session那儿把服务器地址填好,到Tunnel界面上,选Dynamics和Auto ...
- DjangoUeditor项目的集成
DjangoUeditor这个项目,出品人已经不再提供维护支持. 最近在一个使用到aliyun oss的项目里集成了一次这个东西,当然我之前在普通文件上传的北京下已经集成过很多次了. 主要修改的东西就 ...
- Django中的Python高级特性
本小文的内容实际是作为<Pro Django>第二版第二章的读书笔记简单总结. 1.类的构建:元类,使用带元类的基类----这个特性的案例主要就是models.Model类,用这种方式高效 ...
- nginx flv点播服务器搭建
首先选用Nginx+Nginx-rtmp-module作为点播服务器,安装文章:https://www.atlantic.NET/community/howto/install-rtmp-ubuntu ...
- Jmeter(二十六)_数据驱动测试
花了一点时间做了一个通用的执行引擎,好处就是我不用再关注测试脚本的内容,而是用测试用例的数据去驱动我们执行的方向.(这个只适合单个接口的测试,具体运用到接口自动化时,还是要靠手动去编写脚本!) 首先我 ...
- 一些Gym三星单刷的比赛总结
RDC 2013, Samara SAU ACM ICPC Quarterfinal Qualification Contest G 思路卡成智障呀! Round 1:对着这个魔法阵找了半天规律,效果 ...
- 使用Rapidxml读取xml文件
现有xml文件如上,写在一个string中.需要获取节点上元素的类别和属性信息,并存储到结构体表中. 结构体如下: 得到的结果如下:
- Android 源码中的设计模式
最近看了一些android的源码,发现设计模式无处不在啊!感觉有点乱,于是决定要把设计模式好好梳理一下,于是有了这篇文章. 面向对象的六大原则 单一职责原则 所谓职责是指类变化的原因.如果一个类有多于 ...
- [Java算法分析与设计]--单向链表(List)的实现和应用
单向链表与顺序表的区别在于单向链表的底层数据结构是节点块,而顺序表的底层数据结构是数组.节点块中除了保存该节点对应的数据之外,还保存这下一个节点的对象地址.这样整个结构就像一条链子,称之为" ...