1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
|
""" @Version: 1.0 @Author: KnightSeal @Contact: knightseal@yeah.net @Name: ssh_lib.py @Create: 16/3/16 14:18 @Desc: 一个自定义ssh客户端 """
import time import logging import paramiko import functools
CONN_TIMEOUT = 5 CMD_TIMEOUT = 10
def myprint(color,mes): """ 用于打印颜色 :param color: 颜色 :param mes: 打印内容 :return: 没有返回 """ info = {'red':31, 'green': 33, 'yellow':35, 'blue':34,'dark_green':36,'default':37} if color in info: fore = info[color] else: fore = 37 color = "\x1B[%d;%dm" % (1,fore) print("%s%s\x1B[0m" % (color,mes))
def time_func(func): """ 装饰器: 命令运行时间 :param func: 函数 :return: """ @functools.wraps(func) def wapper(*args,**kwargs): banner_footer = "*" * 90 myprint('green',banner_footer) start = time.time() try: result = func(*args,**kwargs) return result except Exception : myprint("red","Exception: 网络连接错误或者密码不正确") finally: end = time.time() myprint("red","耗时:%s 秒" % round((end-start),2)) myprint('green',banner_footer) return wapper
def show_help(): """ 显示帮助 :return: """ help_info = { '-h': '打印帮助', '-G': '指定服务器分组,逗号分隔多个组,将读取conf/host_list.conf进行解析,例如 -G redis', '-k': '运行命令是否使用sudo', '-c': '运行命令,使用\"双引号包裹命令', '-p': 'put上传到远端服务器,使用\"双引号包裹,|分隔,例如: -p "localfile|remotefile" ', '-b': 'put上传到远端服务器是否备份源文件', '-g': 'get下载到本地,使用\"双引号包裹,|分隔 例如: -g "remotefile|localfile" ', 'example\n' : '\t执行redis服务器命令:\tpython ssh_client.py -G redis -c "cat /etc/hosts|grep -v "127.0.0.1" "\n' "\t批量下载redis服务器/etc/hosts文件到本地/data/hosts:\tpython ssh_client.py -G redis -g /etc/hosts|/data/hosts\n" "\t批量上传本地文件test.log到远端redis服务器/tmp/test.log[如果加上-b将对远端文件进行备份]:\tpython ssh_client.py -G redis -p test.log|/tmp/test.log\n" } for item in sorted(help_info.items(),key=lambda x:x[0]): myprint("green","%s %s" % item)
@time_func def run_cmd(username,password,ip,cmd,port=22,key=None,sudo=False,logfile="logs/paramiko.log"): """ 运行远端命令: :param username: ssh用户名 :param password: ssh密码 :param ip: 主机ip,或者主机名 :param cmd: 命令 :param port: ssh 端口 :param key: 私钥路径地址 :param sudo: 是否使用sudo :param logfile: 日志文件路径 """
logger = logging.getLogger() hdlr = logging.FileHandler(logfile) formatter = logging.Formatter('myssh ' +'%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(formatter) logger.addHandler(hdlr) logger.setLevel(logging.INFO) host_info = "* 主机:\t%s : 运行命令:[%s]" % (ip,cmd) ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) if key and key.endswith('rsa'): key = paramiko.RSAKey.from_private_key_file(key) elif key and key.endswith('dsa'): key = paramiko.DSSKey.from_private_key_file(key)
ssh.connect(hostname=ip,port=port,username=username,password=password,pkey=key,\ timeout=CONN_TIMEOUT,compress=True)
if sudo: cmd = "sudo %s" % cmd stdin,stdout,stderr = ssh.exec_command(command=cmd,timeout=CMD_TIMEOUT,get_pty =True) time.sleep(0.01) stdin.write(password + "\n") stdin.flush() if len(stderr.read()) > 0: stderr = "* %s" % (''.join(stderr.readlines()[1:])) stdout = stderr cmd_run_status = 255 else: cmd_run_status = stdout.channel.recv_exit_status() stdout = '* %s' % ('* '.join(stdout.readlines()[1:]))
banner_footer = "*" * 90 myprint('green',host_info) if cmd_run_status == 0: myprint("green","* 运行:\t[OK]") else: myprint("red","* 运行: [ERRO]") myprint("green",stdout)
else: stdin,stdout,stderr =ssh.exec_command(command=cmd,timeout=CMD_TIMEOUT,get_pty =True) if len(stderr.read()) > 0: stderr = "* %s" % (''.join(stderr.readlines()[1:])) stdout = stderr cmd_run_status = 255 else: cmd_run_status = stdout.channel.recv_exit_status() stdout = '* %s' % ('* '.join(stdout.readlines()))
banner_footer = "*" * 90 myprint('green',host_info) if cmd_run_status == 0: myprint("green","* 运行:\t[OK]") else: myprint("red","* 运行: [ERRO]") myprint("green",stdout) log = "用户:%s, HOST: %s, CMD: %s, CMD_EXIT_CODE: %s" % (username,ip,cmd,cmd_run_status) logger.info(log) ssh.close()
def sftp_transfer(username,password,ip,local,remote,port=22,key=None,transfer_type="get",backup=True,logfile="logs/paramiko.log"): """ sftp 文件传输, :param username: ssh用户名 :param password: ssh密码 :param ip: 主机ip,或者主机名 :param port: ssh 端口 :param local: 本地路径 :param remote: 远端路径 :param transfer_type: 传输类型 get|下载,put上传 :param backup: 文件进行覆盖前,是否进行backup :param logfile: 日志文件路径 :return: """ logger = logging.getLogger() hdlr = logging.FileHandler(logfile) formatter = logging.Formatter('myssh ' +'%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(formatter) logger.addHandler(hdlr) logger.setLevel(logging.INFO) ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) if key and key.endswith('rsa'): key = paramiko.RSAKey.from_private_key_file(key) elif key and key.endswith('dsa'): key = paramiko.DSSKey.from_private_key_file(key) ssh.connect(hostname=ip,port=port,username=username,password=password,pkey=key,\ timeout=CONN_TIMEOUT,compress=True) tansport =ssh.get_transport() sftp = paramiko.SFTPClient.from_transport(tansport) if transfer_type == 'get': try: sftp.stat(remote) download_file = "%s.%s" % (local,ip) sftp.get(remote,download_file) status = 'OK' myprint("green","从%s下载:%s:到本地,文件为:%s OK" % (ip,remote,download_file)) except Exception as e: myprint("red","从%s下载: %s ERRO :%s" % (ip,remote,str(e))) status = str(e) finally: sftp.close() log = "用户: %s, HOST: %s, CMD: 下载文件, LOCAL: %s, REMOTE: %s, STATUS: %s" % (username,ip,local,remote,status) logger.info(log) tansport.close() else: if backup: timestamp = int(time.time()) backup_file = "%s.backup.%s" % (remote,timestamp) try: sftp.stat(remote) sftp.rename(remote,backup_file) myprint("red","%s 已经备份为: %s" % (remote,backup_file)) except FileNotFoundError: pass except OSError: pass try: sftp.put(local,remote) status = 'OK' myprint("green","本地文件:%s,上传到:%s:%s OK" % (local,ip,remote)) except Exception as e: myprint("red","ERRO: %s" % str(e)) status = str(e) finally: log = "用户: %s, HOST: %s, CMD: 上传文件, LOCAL: %s, REMOTE: %s, STATUS: %s" % (username,ip,local,remote,status) logger.info(log) tansport.close() sftp.close()
if __name__ == '__main__': run_cmd('seal','123456','192.168.2.199','ls',port=22,key=None,sudo=False,)
|