堡垒机实例以及执行命令
Python的paramiko模块,该模块基于SSH用于连接远程服务器并执行相关操作。
SSHClient
用于连接远程服务器并执行基本命令
基于用户名密码连接:
方法1:
import paramiko # 创建SSH对象 ssh = paramiko.SSHClient() # 允许连接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接服务器 ssh.connect(hostname='c1.salt.com', port=22, username='root', password='123') # 执行命令 stdin, stdout, stderr = ssh.exec_command('df') # 获取命令结果 result = stdout.read() # 关闭连接 ssh.close()
方法2:
使用transport封装来实现
import paramiko # 封装transport 获取到主机、端口、用户名、密码 transport = paramiko.Transport(('192.168.56.11', 22)) transport.connect(username='root', password='123') # 基于transport来连接 ssh = paramiko.SSHClient() ssh._transport = transport # 执行命令,标准输入、输出、错误 stdin, stdout, stderr = ssh.exec_command('df') print stdout.read() transport.close()
基于密钥的连接
方法1:
import paramiko private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa') # 创建SSH对象 ssh = paramiko.SSHClient() # 允许连接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接服务器 ssh.connect(hostname='c1.salt.com', port=22, username='root', key=private_key) # 执行命令 stdin, stdout, stderr = ssh.exec_command('df') # 获取命令结果 result = stdout.read() # 关闭连接 ssh.close()
方式二:
import paramiko private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa') transport = paramiko.Transport(('192.168.56.12', 22)) transport.connect(username='root', pkey=private_key) ssh = paramiko.SSHClient() ssh._transport = transport stdin, stdout, stderr = ssh.exec_command('df') transport.close()
SFTPClient
用于连接远程服务器并执行上传下载
基于用户名密码上传下载
import paramiko transport = paramiko.Transport(('192.168.56.12',22)) transport.connect(username='root',password='123') sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put('/tmp/location.py', '/tmp/test.py') # 将remove_path 下载到本地 local_path sftp.get('remove_path', 'local_path') transport.close()
基于公钥密钥上传下载
import paramiko private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa') # 封装transport对象 transport = paramiko.Transport(('192.168.56.12', 22)) transport.connect(username='root', pkey=private_key ) # 调用执行 sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put('/tmp/location.py', '/tmp/test.py') # 将remove_path 下载到本地 local_path sftp.get('remove_path', 'local_path') # 关闭连接 transport.close()
使用paramiko使用简单的上传下载
方式一:
连接方式选择不实用transport的方式
#!/usr/bin/env python # coding:utf-8 import paramiko import uuid class haproxy(object): # 初始化 def __init__(self): self.host = '192.168.56.11' self.port = 22 self.username = 'root' self.pwd = '123456' # 创建文件,使用UUID来生成名字,一个字符串 def creat_file(self): file_name = str(uuid.uuid4()) with open(file_name,'w') as f: f.write('sbsbsbsbsb') # 将文件名封装到内存中 return file_name def run(self): self.upload() self.rename() # 上传文件 def upload(self): # 在本地创建文件,名称是file_name file_name = self.creat_file() transport = paramiko.Transport((self.host, self.port)) transport.connect(username=self.username, password=self.pwd) sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put(file_name, '/home/root/dddddddddddddd.py') transport.close() # 文件重命名 def rename(self): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(hostname=self.host, port=self.port, username=self.username, password=self.pwd) stdin,stdout,stderr = ssh.exec_command('mv /home/root/dddddddddddddd.py /home/root/ssssssssssss.py') result = stdout.read() ssh.close() a = haproxy() a.run()
方法2:
使用transport连接方式
#!/usr/bin/env python # coding:utf-8 import paramiko import uuid class haproxy(object): def __init__(self): self.host = '192.168.56.12' self.port = 22 self.username = 'root' self.pwd = '123456' def creat_file(self): file_name = str(uuid.uuid4()) with open(file_name,'w') as f: f.write('sbsbsbsbsb') return file_name def run(self): self.connect() self.upload() self.rename() self.close() def connect(self): transport = paramiko.Transport((self.host, self.port)) transport.connect(username=self.username, password=self.pwd) self.__transport = transport def close(self): self.__transport.close() def upload(self): self.__transport = self.__transport file_name = self.creat_file() sftp = paramiko.SFTPClient.from_transport(self.__transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put(file_name, '/ssssssssssss.py') def rename(self): ssh = paramiko.SSHClient() self.__transport = self.__transport ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(hostname=self.host, port=self.port, username=self.username, password=self.pwd) stdin,stdout,stderr = ssh.exec_command('mv /ssssssssssss.py /dddddddddddddd.py') result = stdout.read() a = haproxy() a.run()
之前上面的两种实现方式都不能实现持续连接服务器,下面咱们来搞搞让他更持久。。。。。
持久一:
他会直接连接到远程服务器上
#!/usr/bin/env python # coding:utf-8 import sys import select import socket import paramiko # 使用transport封装一个tran, tran = paramiko.Transport(('192.168.56.12',22)) tran.start_client() # 使用用户名密码的方式连接 tran.auth_password('root','123456') # 打开一个通道 chan = tran.open_session() # 获取一个终端 chan.get_pty() # 激活器 chan.invoke_shell() while True: # 使用select来检测,chan和sys.stdin这两个句柄有没有发生变化 # stdin用来处理用户的输入 # chan负责接收和上传 readable,writeable,error = select.select([chan,sys.stdin,],[],[],1) if chan in readable: try: x = chan.recv(1024) if len(x) == 0: print '\r\n*** EOF\r\n', break sys.stdout.write(x) sys.stdout.flush() except socket.timeout: pass # 如果stdin中有内容,那么就发送给远端服务器 if sys.stdin in readable: inp = sys.stdin.readable() chan.sendall(inp) chan.close() tran.close()
上面代码的问题:用户输入内容后,只有点击回车,才会放到stdin中,才会发送给服务器端。
持久二:
更新tab补全功能,与标准模式个原生模式的转换
#!/usr/bin/env python # coding:utf-8 import sys import select import socket import paramiko import termios import tty tran = paramiko.Transport(('192.168.56.12',22)) tran.start_client() tran.auth_password('root','123456') chan = tran.open_session() chan.get_pty() chan.invoke_shell() # 获取原tty属性 oldtty = termios.tcgetattr(sys.stdin) try: # 为tty设置一个新的属性 # 默认的属性是:输入一行回车,然后执行 # crtl+C进程退出,遇到特殊字符,特殊处理 # 这是为原始模式,不认识所有特殊字符 # 放置特殊字符应该用在当前终端,将所有的用户输入均发送到远程服务器 tty.setraw(sys.stdin.fileno()) chan.settimeout(0.0) while True: # 监视 用户的输入和远程服务器返回数据 # 阻塞,知道句柄有内容可读 r,w,e = select.select([chan,sys.stdin],[],[],1) if chan in r: try: x =chan.recv(1024) if len(x)==0: print '\r\n*** EOF\r\n', break except socket.timeout: pass if sys.stdin in r: x = sys.stdin.read(1) if len(x)==0: break chan.send(x) finally: # 重新将终端设置为标准的属性 termios.tcgetattr(sys.stdin,termios.TCSADRAIN,oldtty) chan.close() tran.close()
作者:曹小贱
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。