python使用paramiko实现ssh定时执行命令
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @Author: Rosaany
import functools
from paramiko.ssh_exception import NoValidConnectionsError, AuthenticationException
from argparse import RawTextHelpFormatter
import paramiko # 第三方库, pip安装, pip install paramiko -i https://pypi.douban.com/sample
import time
import sys
import argparse
import socket
def g_time(func):
# 计时装饰器
def inner(*arg, **kwarg):
s_time = time.time()
res = func(*arg, **kwarg)
e_time = time.time()
t_time = e_time - s_time
days = t_time // (24 * 60 * 60)
t_time %= (24 * 60 * 60)
hours = t_time // (60 * 60)
t_time %= (60 * 60)
minutes = t_time // 60
t_time %= 60
seconds = t_time % 60
print('>>>程序运行时间:{days:.0f}天{hours:.0f}时{minutes:.0f}分{seconds:.0f}秒'.format(days=days, hours=hours,
minutes=minutes, seconds=seconds))
return res
return inner
def retry(exceptions: list, times=3, wait=1):
"""重连机制"""
if not isinstance(exceptions, (tuple, list)):
new_exceptions = [exceptions]
else:
new_exceptions = exceptions
def inner_retry(func, count, *args, **kwargs):
if count > times:
return
try:
return func(*args, **kwargs)
except tuple(new_exceptions) as e:
if count < times:
time.sleep(wait)
return inner_retry(func, count + 1, *args, **kwargs)
else:
print("重连失败!") # raise e
def decorator(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
return inner_retry(func, 0, *args, **kwargs)
return wrapped
return decorator
def ssh_connected(ssh, cmds, waits, verbose):
try:
# 激活交互式shell
# https://stackoverflow.com/questions/6203653/how-do-you-execute-multiple-commands-in-a-single-session-in-paramiko-python
channel = ssh.invoke_shell()
time.sleep(1)
stop = True
while stop:
try:
for cmd in cmds:
channel.send(cmd.encode())
# 模拟回车'Enter'这个动作
channel.send(b'\n')
# 每个命令间隔时间
time.sleep(1)
r = channel.recv(40960).decode()
if verbose:
print(r)
# 执行完一轮命令,等待时间
time.sleep(waits)
except KeyboardInterrupt: # 捕获ctrl + c时终止程序
stop = False
if not waits:
stop = False
channel.close()
ssh.close()
except AttributeError as e:
raise e
@g_time
@retry([AttributeError, OSError], times=3, wait=3)
def ssh_client(host: str, user: str, pwd: str, cmds: str, waits: int, verbose: int):
"""ssh客户端"""
# 私钥文件的存放路径
# private = paramiko.RSAKey.from_private_key_file(r'C:\Users\xxxx\Documents\xxx')
# 创建一个实例化
ssh = paramiko.SSHClient()
# 加载系统SSH密钥
ssh.load_system_host_keys()
# 自动添加策略,保存服务器的主机名和密钥信息,如果不添加,那么不在本地knows_hosts文件中记录的主机将无法连接,默认拒接
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接设备
try:
ssh.connect(hostname=host, username=user, timeout=5, compress=True, password=pwd # pkey=private, #可以采用密钥连接
)
print("正在连接主机ip: {}.....".format(host))
except NoValidConnectionsError:
print('连接出现了问题')
except AuthenticationException:
print('用户名或密码错误')
except socket.timeout:
print('请检查你的远程主机通讯连接是否正常')
except Exception as err:
print('其他错误问题: {}'.format(err))
finally:
ssh_connected(ssh, cmds, waits, verbose)
def tool():
"""
命令行参数
"""
ssh_client_help = "一个简单的SSH脚本定时执行命令脚本,如想终止脚本,请按下快捷键ctrl+c \n" \
"简单的示例:$python sshclient_exec_command.py -cmds 'top, ls, ifconfig'"
if len(sys.argv) == 1:
sys.argv.append('--help')
parser = argparse.ArgumentParser(description=ssh_client_help, formatter_class=RawTextHelpFormatter)
parser.add_argument('-u', type=str, default='root', help='ssh访问主机的用户名,默认用户名是root')
parser.add_argument('-p', type=str, default='root', help='ssh访问主机的密码,默认密码是root')
parser.add_argument('-host', type=str, default='192.168.1.248', help='ssh访问主机ip,默认访问主机是192.168.1.248')
parser.add_argument('-cmds', type=str, default="ls -ll, ifconfig",
help='执行输入的命令,多个以英文逗号分隔,默认输入命令是"ls -ll,ifconfig"')
parser.add_argument('-t', type=str, default=0, help='输入一个定时等待时间,单位是秒,默认定时时间为0秒')
parser.add_argument('-v', type=int, default=1, help='显示详细信息,默认输出详细信息')
arguments = parser.parse_args()
return arguments
def main():
"""主程序"""
arguments = tool()
host = arguments.host
user = arguments.u
pwd = arguments.p
cmds = arguments.cmds
verbose = arguments.v
waits = arguments.t
if not isinstance(verbose, int):
verbose = int(verbose)
if not isinstance(waits, int):
waits = int(waits)
if isinstance(cmds, str):
cmds = cmds.split(',')
print("执行命令:{cmd}".format(cmd=cmds))
ssh_client(host=host, user=user, pwd=pwd, cmds=cmds, verbose=verbose, waits=waits)
if __name__ == '__main__':
# linux实时查看ssh连接通道state变化,-n 1表示每一秒查询一遍,注意TCP四次挥手是否正常释放
# watch -n 1 -d 'netstat -anlt | grep 192.168.1.1'
main()
使用示例
$python .\sshclient_exec_commands.py
usage: sshclient_exec_commands.py [-h] [-u U] [-p P] [-host HOST] [-cmds CMDS] [-t T] [-v V]
一个简单的SSH脚本定时执行命令脚本,如想终止脚本,请按下快捷键ctrl+c
简单的示例:$python sshclient_exec_command.py -cmds 'top, ls, ifconfig'
optional arguments:
-h, --help show this help message and exit
-u U ssh访问主机的用户名,默认用户名是root
-p P ssh访问主机的密码,默认密码是123456
-host HOST ssh访问主机ip,默认访问主机是192.168.1.1
-cmds CMDS 执行输入的命令,多个以英文逗号分隔,默认输入命令是"ls -ll,ifconfig"
-t T 输入一个定时等待时间,单位是秒,默认定时时间为0秒
-v V 显示详细信息,默认输出详细信息
- 定时执行
加上-t参数,默认不执行定时,单位是秒
解释:ssh连接主机192.168.1.1,用户名root密码123456,在当前用户目录下每秒输入一次“ls”命令。
python .\sshclient_exec_commands.py -host 192.168.1.1 -u root -p 123456 -cmds "ls" -t 1
- 执行多个命令
比如:-cmds "ls -l, ifconfig",多个命令,中间加入一个英文逗号
python .\sshclient_exec_commands.py -host 192.168.1.1 -u root -p 123456 -cmds "ls -l, ifconfig" -t 1