标签:erro passwd obj 返回结果 输出 exec toad remote src
大概思路:
理想效果就是达到类似于saltstack或者是ansible类似的一点小功能,比如 在命令行下输入python3 automatic.py -g dsp -c ‘w‘
输出:
b‘ 18:24:20 up 3:44, 2 users, load average: 0.00, 0.00, 0.00\nUSER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT\nroot pts/0 192.168.0.101 17:26 4:11 0.02s 0.02s -bash\nroot pts/2 192.168.0.101 17:24 1.00s 0.51s 0.12s python3 automat\n‘
使用到的模块:paramiko:用于远程执行命令,支持密钥和用户密码登录
optparse:解析命令行
logging:记录日志
configparser:解析配置文件
multiprocessing:启用多进程方式
目录结构如下:
conf是默认配置文件,log是默认日志文件,automatic主程序,logger日志程序
源码如下:automatic
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import paramiko
from optparse import OptionParser
import configparser
import os,sys
from multiprocessing import Pool
import logger #插入日志模块
‘‘‘默认配置文件路径和日志文件路径‘‘‘
CONF_PATH = os.path.abspath(os.path.join(os.path.dirname(‘.‘),‘conf‘))
LOG_PATH = os.path.abspath(os.path.join(os.path.dirname(‘.‘),‘log‘))
‘‘‘解析配置文件,设置默认sections和options,pkey_file指定密钥文件名,fork表示默认开启5个进程‘‘‘
def ConfigParser(group):
config = configparser.ConfigParser()
config[‘DEFAULT‘] = {‘user‘:‘root‘,
‘port‘:22,
‘passwd‘:‘123456‘,
‘pkey_file‘:‘‘,
‘host‘: ‘‘
}
config[‘default‘] = {‘conf_path‘:CONF_PATH,
‘log_path‘: LOG_PATH,
‘fork‘:5
}
if not os.path.exists(CONF_PATH): #判断配置文件是否存在,不存在创建并写入默认配置
fp = open(CONF_PATH,‘w‘)
config.write(fp)
fp.close()
else:
config.read(CONF_PATH) #读取配置文件,获取到分组的options的各项值
try:
section = config.sections()
ip = config.get(group,‘host‘)
user = config.get(group,‘user‘)
port = config.get(group,‘port‘)
passwd = config.get(group,‘passwd‘)
pkey_file = config.get(group,‘pkey_file‘)
fork = config.get(‘default‘,‘fork‘)
log_path = config.get(‘default‘,‘log_path‘)
except Exception:
print ("group is not exists")
else:
return section,ip,user,port,passwd,pkey_file,fork,log_path
def remote_cmd(ip,user,passwd,cmd,pkey_file=None): #调用ssh客户端执行命令返回结果
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
if pkey_file: #如果传入了密钥文件,采用密钥方式登录
key = paramiko.RSAKey.from_private_key_file(pkey_file)
ssh.connect(hostname=ip,username=user,pkey=key)
ssh.connect(hostname=ip,username=user,password=passwd)
stdin,stdout,stderr = ssh.exec_command(cmd)
if stdout:
result = stdout.read()
else:
result = stderr.read()
return result
‘‘‘调用sftp进行上传下载文件‘‘‘
class SFTP(object):
def __init__(self,ip,port,user,passwd,src_file,dst_file,pkey_file=None):
self.ip = ip
self.port = int(port)
self.user = user
self.passwd = passwd
self.src_file = src_file
self.dst_file = dst_file
self.pkey_file = pkey_file
def remote_transport(self):
s = paramiko.Transport((self.ip,self.port))
if self.pkey_file: #如果传入了密钥文件,采用密钥方式登录
key = paramiko.RSAKey.from_private_key_file(self.pkey_file)
s.connect(username=self.user,password=None,pkey=key)
s.connect(username=self.user,password=self.passwd)
sftp = paramiko.SFTPClient.from_transport(s)
return sftp
def get(self): #下载文件
sftp = self.remote_transport()
sftp.get(self.src_file,self.dst_file)
def put(self): #上传文件
sftp = self.remote_transport()
sftp.put(self.src_file,self.dst_file)
‘‘‘解析命令行,使用optparse,我用的python3.6版本‘‘‘
def opt():
parser = OptionParser("Usage: %prog [-g GROUP] [-c COMMAND]")
parser.add_option(‘-g‘,‘--group‘,
dest = ‘group‘,
action = ‘store‘,
default = True,
help=‘GROUP‘)
parser.add_option(‘-c‘,‘--command‘,
dest = ‘command‘,
action=‘store‘,
default = True,
help="COMMAND")
options,args = parser.parse_args()
return options,args
‘‘‘根据-c 后面跟的命令判断是进行ssh远程执行命令还是使用sftp上传下载文件操作,并记录日志,src为源文件,dst为目标文件,f是进行get还是put,get表示下载,put表示上传‘‘‘
def multi_pool(cmd,ip,user,port,passwd,pkey_file,log_path):
if cmd.startswith(‘get‘) or cmd.startswith(‘put‘):
src = cmd.split()[1]
dst = cmd.split()[2]
f = cmd.split()[0]
sf = SFTP(ip,port,user,passwd,src,dst,pkey_file)
if hasattr(sf,f): #使用反射,减少判断
func = getattr(sf,f)
func()
logger.loggs("%s %s" % (ip,cmd),log_path)
else:
result = remote_cmd(ip,user,passwd,cmd,pkey_file)
logger.loggs("%s %s" % (ip,cmd),log_path)
print(result)
‘‘‘主函数,进行读取命令行参数以及获取配置文件的各项值,开启多进程,使用进程池‘‘‘
def main():
options,args = opt()
groups = options.group
cmd = options.command
try:
sec,ip,user,port,passwd,pkey_file,fork,log_file = ConfigParser(groups)
except Exception:
print("configparser error")
else:
p = Pool(int(fork))
if groups in sec:
for i in ip.split(‘,‘):
p.apply_async(func=multi_pool,args=(cmd,i,user,port,passwd,pkey_file,log_file))
p.close()
p.join()
if __name__ ==‘__main__‘:
main()
logger源码:
#!/usr/bin/env python3 # -*- coding:utf-8 -*- import logging ‘‘‘msg是需要记录的日志信息,f是日志路径‘‘‘ def loggs(msg,f): logger = logging.getLogger() logger.setLevel(logging.DEBUG) fh = logging.FileHandler(f) fh.setLevel(logging.DEBUG) formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘) #日志格式 fh.setFormatter(formatter) logger.addHandler(fh) logger.debug(msg) if __name__ == ‘__main__‘: msg = ‘‘ f = ‘‘ loggs(msg,f)
基本实现了预期的功能,由于时间原因流程图就没画,使用python3.6版本在centos6.7版本运行成功
标签:erro passwd obj 返回结果 输出 exec toad remote src
原文地址:http://www.cnblogs.com/wrlinux/p/7051170.html