getpass、os.path、tty、termios、paramiko系统模块:通过ssh远程登录服务器执行命令
一、getpass共包括下面两个函数:
getpass.getuser() 返回用户的登录名,适用于:Unix, Windows 。
getpass.getpass() 提示用户输入密码,适用于unix、windows。
getpass.getpass([prompt[, stream]]) ,参数 prompt 用于提示用户开始输入,默认为'Password: '。在 Unix 上,该提示符被写入到类文件对象流中。参数 stream 默认为控制终端 (/dev/tty) 或入过前者不可用时为 sys.stderr (该参数在 Windows 上无效)。
import getpass
p = getpass.getpass('please input your password: ')
pls input your password: 123
p # '123'
In [60]: os.path.abspath('.') Out[60]: '/root/workspace'
os.path.basename(path) #返回文件名
os.path.dirname(path) #返回文件路径
In [66]: os.path.basename('/root/workspace/app.py') Out[66]: 'app.py' In [67]: os.path.dirname('/root/workspace/app.py') Out[67]: '/root/workspace' In [68]: os.path.abspath('/root/workspace/app.py') Out[68]: '/root/workspace/app.py' In [69]: os.path.dirname('./app.py') Out[69]: '.' In [70]: os.path.basename('./app.py') Out[70]: 'app.py'
os.path.commonprefix(list) #返回list(多个路径)中,所有path共有的最长的路径。
In [64]: os.path.commonprefix(['/root/workspace/msched/', '/root/workspace']) Out[64]: '/root/workspace'
os.path.exists(path) #路径存在则返回True,路径损坏返回False
In [71]: os.path.exists('/root/workspace/app.py') Out[71]: True
os.path.expanduser(path) #把path中包含的"~"和"~user"转换成用户目录
In [75]: os.path.expanduser('~/app.py') Out[75]: '/root/app.py'
os.path.expandvars(path) #根据环境变量的值替换path中包含的”$name”和”${name}”
In [77]: os.path.getatime('/root/workspace/app.py') Out[77]: 1497501217.552647 In [78]: os.path.getmtime('/root/workspace/app.py') Out[78]: 1495172967.9839048 In [79]: os.path.getctime('/root/workspace/app.py') Out[79]: 1495177406.1508164
os.path.getsize(path) #返回文件大小,如果文件不存在就返回错误
In [82]: os.path.getsize('/root/workspace/app.py') Out[82]: 412
os.path.isabs(path) #判断是否为绝对路径
In [84]: os.path.isabs('.') Out[84]: False In [85]: os.path.isfile('/root/workspace/app.py') Out[85]: True In [86]: os.path.isdir('/root/workspace/app.py') Out[86]: False In [88]: os.path.islink('/root/workspace/app.py') Out[88]: False In [90]: os.path.ismount('/root/workspace/app.py') Out[90]: False
os.path.normcase(path) #转换path的大小写和斜杠
In [97]: os.path.realpath('.') Out[97]: '/root/workspace' In [101]: os.path.relpath('/root/workspace/app.py', '/root') Out[101]: 'workspace/app.py'
os.path.samefile(path1, path2) #判断目录或文件是否相同
In [106]: os.path.split('/root/workspace/app.py') Out[106]: ('/root/workspace', 'app.py')
os.path.splitdrive(path) #一般用在windows下,返回驱动器名和路径组成的元组
三、tty模块就是有两个函数:
setraw 设置标准输入为raw模式
setcbreak
四、termios:
终端参数控制,详见:http://www.cnblogs.com/li-hao/archive/2012/02/19/2358158.html
old_tty = termios.tcgetattr(sys.stdin) # 获取服务端的tty,保存下来 try: # 设置一个新的tty tty.setraw(sys.stdin.fileno()) # 设置tty为raw模式 tty.setcbreak(sys.stdin.fileno()) # 不再使用原来服务端的tty, tty使用由上条语句重新设置的tty # 返回原来的tty termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
SSL和SSH的区别:
ssl是通讯链路的附加层。可以包含很多协议。https, ftps, .....
ssh只是加密的shell,最初是用来替代telnet的。通过port forward,也可以让其他协议通过ssh的隧道而起到加密的效果。
SSL是一种国际标准的加密及身份认证通信协议,您用的浏览器就支持此协议。SSL(Secure Sockets Layer)最初是由美国Netscape公司研究出来的,后来成为了Internet网上安全通讯与交易的标准。SSL协议使用通讯双方的客户证书以及CA根证书,允许客户/服务器应用以一种不能被偷听的方式通讯,在通讯双方间建立起了一条安全的、可信任的通讯通道。它具备以下基本特征:信息保密性、信息完整性、相互鉴定。 主要用于提高应用程序之间数据的安全系数。SSL协议的整个概念可以被总结为:一个保证任何安装了安全套接字的客户和服务器间事务安全的协议,它涉及所有TC/IP应用程序。
SSH的英文全称是Secure SHell。通过使用SSH,你可以把所有传输的数据进行加密,这样“中间人”这种攻击方式就不可能实现了,而且也能够防止DNS和IP欺骗。还有一个额外的好处就是传输的数据是经过压缩的,所以可以加快传输的速度。SSH有很多功能,它既可以代替telnet,又可以为ftp、pop、甚至ppp提供一个安全的“通道”。SSH是由客户端和服务端的软件组成的,有两个不兼容的版本分别是:1.x和2.x。用SSH 2.x的客户程序是不能连接到SSH 1.x的服务程序上去的。OpenSSH 2.x同时支持SSH 1.x和2.x。SSH的安全验证是如何工作的从客户端来看,SSH提供两种级别的安全验证。第一种级别(基于口令的安全验证)只要你知道自己帐号和口令,就可以登录到远程主机。所有传输的数据都会被加密,但是不能保证你正在连接的服务器就是你想连接的服务器。可能会有别的服务器在冒充真正的服务器,也就是受到“中间人”这种方式的攻击。第二种级别(基于密匙的安全验证)需要依靠密匙,也就是你必须为自己创建一对密匙,并把公用密匙放在需要访问的服务器上。如果你要连接到SSH服务器上,客户端软件就会向服务器发出请求,请求用你的密匙进行安全验证。服务器收到请求之后,先在你在该服务器的家目录下寻找你的公用密匙,然后把它和你发送过来的公用密匙进行比较。如果两个密匙一致,服务器就用公用密匙加密“质询”(challenge)并把它发送给客户端软件。客户端软件收到“质询”之后就可以用你的私人密匙解密再把它发送给服务器。用这种方式,你必须知道自己密匙的口令。但是,与第一种级别相比,第二种级别不需要在网络上传送口令。第二种级别不仅加密所有传送的数据,而且“中间人”这种攻击方式也是不可能的(因为他没有你的私人密匙)。但是整个登录的过程可能需要10秒。
OpenSSL------一个C语言函数库,是对SSL协议的实现。
OpenSSH-----是对SSH协议的实现。
HTTPS可以使用TLS或者SSL协议,而openssl是TLS、SSL协议的开源实现,提供开发库和命令行程序。openssl很优秀,所以很多涉及到数据加密、传输加密的地方都会使用openssl的库来做。
可以理解成所有的HTTPS都使用了openssl。
五、paramiko模块
paramiko模块,提供了ssh及sft进行远程登录服务器执行命令和上传下载文件的功能。这是一个第三方的软件包,使用之前需要安装。
(一).paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接。
由于使用的是python这样的能够跨平台运行的语言,所以所有python支持的平台,如Linux, Solaris, BSD, MacOS X, Windows等,paramiko都可以支持,因此,如果需要使用SSH从一个平台连接到另外一个平台,进行一系列的操作时,paramiko是最佳工具之一。
举个常见的例子,现有这样的需求:需要使用windows客户端,远程连接到Linux服务器,查看上面的日志状态,大家通常使用的方法会是:
1:用telnet
2:用PUTTY
3:用WinSCP
4:用XManager等…
那现在如果需求又增加一条,要从服务器上下载文件,该怎么办?那常用的办法可能会是:
1:Linux上安装FTP并配置
2:Linux上安装Sambe并配置…
大家会发现,常见的解决方法都会需要对远程服务器必要的配置,如果远程服务器只有一两台还好说,如果有N台,还需要逐台进行配置,或者需要使用代码进行以上操作时,上面的办法就不太方便了。
使用paramiko可以很好的解决以上问题,比起前面的方法,它仅需要在本地上安装相应的软件(python以及PyCrypto),对远程服务器没有配置要求,对于连接多台服务器,进行复杂的连接操作特别有帮助。
(二):安装
安装paramiko有两个先决条件,python和另外一个名为PyCrypto的模块。
通常安装标准的python模块,只需要在模块的根目录下运行:
python setup.py build
python setup.py install
以上两条命令即可,paramiko和PyCrypto也不例外,唯一麻烦的就是安装PyCrypto时,需要GCC库编译,如果没有GCC库会报错,会导致PyCrypto以及paramiko无法安装。
以下以32 位的windows XP为例,说明paramiko的安装过程
1:安装python,2.2以上版本都可以,我使用的是2.5,安装过程略,并假设安装目录是c:\python。
2:判断本地是否安装了GCC,并在PATH变量可以找到,如果没有,可使用windows 版的GCC,即MinGW,下载地址:http://sourceforge.net/projects/mingw/,然后运行下载后的exe文件进行网络安装,假设目录为C:\mingw,在PATH中加入 C:\mingw\bin,并在c:\python\lib\distutils下新建一个名称是distutils.cfg的文件,填入:
[build] compiler=mingw32
3:下载PyCrypto ,地址是
https://www.dlitz.net/software/pycrypto/
安装PyCrypto:
- 解压缩
- 在dos下进入解压缩的目录,运行
C:\python\python.exe setup.py build
C:\python\python.exe setup.py install
安装测试
运行python.exe,在提示符下输入:
Import Crypto
如果没有出现错误提示,说明Crypto安装成功
4:下载paramiko,地址是http://www.lag.net/paramiko/
- 解压缩
- 在dos下进 入解压缩的目录,运行
C:\python\python.exe setup.py build
C:\python\python.exe setup.py install
- 测试paramiko
运行python.exe,在提示符下输入:
Import paramiko
如果没有出现错误提示,说明paramiko安装成功
(三): 使用paramiko
如果大家感觉安装paramiko还是略有麻烦的话,当使用到paramiko提供的方便时便会觉得这是十分值得的。
下面是两种使用paramiko连接到linux服务器的代码
方式一:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("某IP地址",22,"用户名", "口令")
上面的第二行代码的作用是允许连接不在know_hosts文件中的主机。
方式二:
t = paramiko.Transport((“主机”,”端口”)) t.connect(username = “用户名”, password = “口令”)
如果连接远程主机需要提供密钥,上面第二行代码可改成:
t.connect(username = “用户名”, password = “口令”, hostkey=”密钥”)
下面给出实际的例子:
3.1 windows对linux运行任意命令,并将结果输出
如果linux服务器开放了22端口,在windows端,我们可以使用paramiko远程连接到该服务器,并执行任意命令,然后通过 print或其它方式得到该结果,
代码如下:
#!/usr/bin/python import paramiko ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect("某IP地址",22,"用户名", "口令") stdin, stdout, stderr = ssh.exec_command("你的命令") print stdout.readlines() ssh.close()
其中的”你的命令”可以任意linux支持的命令,如一些常用的命令:
df:查看磁盘使用情况 uptime:显示系统运行时间信息 cat:显示某文件内容 mv/cp/mkdir/rmdir:对文件或目录进行操作 /sbin/service/ xxxservice start/stop/restart:启动、停止、重启某服务 netstat -ntl |grep 8080:查看8080端口的使用情况 或者 nc -zv localhost :查看所有端口的使用情况 find / -name XXX:查找某文件
...
这样一来,对于linux的任何操作几乎都可以通过windows端完成,如果对该功能进行引申,还可以同时管理多台服务器。
3.2 从widnows端下载linux服务器上的文件
#!/usr/bin/python import paramiko t = paramiko.Transport((“主机”,”端口”)) t.connect(username = “用户名”, password = “口令”) sftp = paramiko.SFTPClient.from_transport(t) remotepath=’/var/log/system.log’ localpath=’/tmp/system.log’ sftp.get(remotepath, localpath) t.close()
3.3 从widnows端上传文件到linux服务器
#!/usr/bin/python import paramiko
t = paramiko.Transport((“主机”,”端口”)) t.connect(username = “用户名”, password = “口令”) sftp = paramiko.SFTPClient.from_transport(t) remotepath=’/var/log/system.log’ localpath=’/tmp/system.log’ sftp.put(localpath,remotepath) t.close()
我对paramiko的使用也刚刚开始,以上若有不对的地方,敬请大家指正!先谢了!
(四)其它示例:
1 基于用户名和密码的 sshclient 方式登录
# 建立一个sshclient对象
ssh = paramiko.SSHClient()
# 允许将信任的主机自动加入到host_allow 列表,此方法必须放在connect方法的前面
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 调用connect方法连接远程服务器
ssh.connect(hostname='192.168.2.129', port=22, username='super', password='super')
# 调用exec_command,在远程服务执行命令
stdin, stdout, stderr = ssh.exec_command('df -hl')
# 标准输入放到stdin中,结果放到stdout中,如果有错误将放到stderr中
print(stdout.read().decode())
# 关闭连接
ssh.close()
2 基于用户名和密码的 transport 方式登录
上面的方法1是传统的连接服务器、执行命令、关闭的一个操作。但有时候需要登录上服务器执行多个操作,比如执行命令、上传/下载文件,方法1则无法实现,可以通过如下方式来操作
# 实例化一个transport对象
trans = paramiko.Transport(('192.168.2.129', 22))
# 建立连接
trans.connect(username='super', password='super')
# 将以上的trans对象附加到sshclient对象的_transport属性上
ssh = paramiko.SSHClient()
ssh._transport = trans
# 执行命令,和传统方法一样,即还是用ssh执行命令
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())
# 但关闭连接的时侯,要关闭的是trans,因为是trans连接的远程服务器
trans.close()
3 基于公钥密钥的 SSHClient 方式登录
# 指定本地的RSA私钥文件;如果建立密钥对时有设置密码,password为设定的密码,如没有则不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
# 建立连接
ssh = paramiko.SSHClient()
ssh.connect(hostname='192.168.2.129',
port=22,
username='super',
pkey=pkey)
# 执行命令
stdin, stdout, stderr = ssh.exec_command('df -hl')
# 结果放到stdout中,如果有错误将放到stderr中
print(stdout.read().decode())
# 关闭连接
ssh.close()
4 基于密钥的 Transport 方式登录
# 指定本地的RSA私钥文件,如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
# 建立连接
trans = paramiko.Transport(('192.168.2.129', 22))
trans.connect(username='super', pkey=pkey)
# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans
# 执行命令,和传统方法一样
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())
# 关闭连接
trans.close()
##### 传文件 SFTP ###########
# 实例化一个trans对象# 实例化一个transport对象
trans = paramiko.Transport(('192.168.2.129', 22))
# 建立连接
trans.connect(username='super', password='super')
# 实例化一个 sftp对象,指定连接的通道
sftp = paramiko.SFTPClient.from_transport(trans)
# 发送文件
sftp.put(localpath='/tmp/11.txt', remotepath='/tmp/22.txt')
# 下载文件
# sftp.get(remotepath, localpath)
trans.close()
5 实现输入命令立马返回结果的功能
以上操作都是基本的连接,如果我们想实现一个类似xshell工具的功能,登录以后可以输入命令回车后就返回结果:
import paramiko
import os
import select
import sys
# 建立一个socket
trans = paramiko.Transport(('192.168.2.129', 22))
# 启动一个客户端
trans.start_client()
# 如果使用rsa密钥登录的话
'''
default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
trans.auth_publickey(username='super', key=prikey)
'''
# 如果使用用户名和密码登录
trans.auth_password(username='super', password='super')
# 打开一个通道
channel = trans.open_session()
# 获取终端
channel.get_pty()
# 激活终端,这样就可以登录到终端了,就和我们用类似于xshell登录系统一样
channel.invoke_shell()
# 下面就可以执行你所有的操作,用select实现
# 对输入终端sys.stdin和 通道进行监控,
# 当用户在终端输入命令后,将命令交给channel通道,这个时候sys.stdin就发生变化,select就可以感知
# channel的发送命令、获取结果过程其实就是一个socket的发送和接受信息的过程
while True:
readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
# 如果是用户输入命令了,sys.stdin发生变化
if sys.stdin in readlist:
# 获取输入的内容
input_cmd = sys.stdin.read(1)
# 将命令发送给服务器
channel.sendall(input_cmd)
# 服务器返回了结果,channel通道接受到结果,发生变化 select感知到
if channel in readlist:
# 获取结果
result = channel.recv(1024)
# 断开连接后退出
if len(result) == 0:
print("\r\n**** EOF **** \r\n")
break
# 输出到屏幕
sys.stdout.write(result.decode())
sys.stdout.flush()
# 关闭通道
channel.close()
# 关闭链接
trans.close()
6 支持tab自动补全
import paramiko
import os
import select
import sys
import tty
import termios
'''
实现一个xshell登录系统的效果,登录到系统就不断输入命令同时返回结果
支持自动补全,直接调用服务器终端
'''
# 建立一个socket
trans = paramiko.Transport(('192.168.2.129', 22))
# 启动一个客户端
trans.start_client()
# 如果使用rsa密钥登录的话
'''
default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
trans.auth_publickey(username='super', key=prikey)
'''
# 如果使用用户名和密码登录
trans.auth_password(username='super', password='super')
# 打开一个通道
channel = trans.open_session()
# 获取终端
channel.get_pty()
# 激活终端,这样就可以登录到终端了,就和我们用类似于xshell登录系统一样
channel.invoke_shell()
# 获取原操作终端属性
oldtty = termios.tcgetattr(sys.stdin)
try:
# 将现在的操作终端属性设置为服务器上的原生终端属性,可以支持tab了
tty.setraw(sys.stdin)
channel.settimeout(0)
while True:
readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
# 如果是用户输入命令了,sys.stdin发生变化
if sys.stdin in readlist:
# 获取输入的内容,输入一个字符发送1个字符
input_cmd = sys.stdin.read(1)
# 将命令发送给服务器
channel.sendall(input_cmd)
# 服务器返回了结果,channel通道接受到结果,发生变化 select感知到
if channel in readlist:
# 获取结果
result = channel.recv(1024)
# 断开连接后退出
if len(result) == 0:
print("\r\n**** EOF **** \r\n")
break
# 输出到屏幕
sys.stdout.write(result.decode())
sys.stdout.flush()
finally:
# 执行完后将现在的终端属性恢复为原操作终端属性
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
# 关闭通道
channel.close()
# 关闭链接
trans.close()
Python中使用SSH需要用到OpenSSH,而OpenSSH依赖于paramiko模块,而paramiko模块又依赖于pycrypto模块,因此要在Python中使用SSH,则需要先安装模块顺序是:pycrypto -> ecdsa -> paramiko
六、textwrap 格式化文本段落
fill:去除缩进
dedent:保留缩进
strip(str):的作用是去除开头和结尾的制定字符 当参数空白时删除空白字符
结合dedent去除缩进+fill传入width参数来设置文本按照某个特定宽度显示
import textwrap
text_example='''
You say that you love rain, but you open your umbrella when it rains.
You say that you love the sun, but you find a shadow spot when the sun shines.
You say that you love the wind, but you close your windows when wind blows.
This is why I am afraid, you say that you love me too.
'''
fill_example=textwrap.fill(text_example) #fill,是去除缩进的格式化版本
dedented_text=textwrap.dedent(text_example) #dedent用来保留缩进
text_width_limited=textwrap.fill(dedented_text.strip(),30) #
#fill的另外一种用法可以单独设置第一行的缩进和剩余几行的缩进。现在设置第一行缩进一个空格,其他的悬挂于第一行下
text_hanging_indent=textwrap.fill(dedented_text.strip(),
initial_indent= ' ',# 第一行的缩进值
subsequent_indent=' ' * 4,# 后续几行的缩进值
width=45,
)
print('No dedent:\n',fill_example,'\n')
No dedent:
You say that you love rain, but you open your umbrella when it rains.
You say that you love the sun, but you find a shadow spot when the sun
shines. You say that you love the wind, but you close your windows
when wind blows. This is why I am afraid, you say that you love me
too.
print('Dedented:\n',dedented_text,'\n')
Dedented:
You say that you love rain, but you open your umbrella when it rains.
You say that you love the sun, but you find a shadow spot when the sun shines.
You say that you love the wind, but you close your windows when wind blows.
This is why I am afraid, you say that you love me too.
print 'Width Limited:\n',text_width_limited,'\n'
Width Limited:
You say that you love rain,
but you open your umbrella
when it rains. You say that
you love the sun, but you find
a shadow spot when the sun
shines. You say that you love
the wind, but you close your
windows when wind blows. This
is why I am afraid, you say
that you love me too.
print 'Hanging Effect:\n', text_hanging_indent,'\n'
Hanging Effect:
You say that you love rain, but you open
your umbrella when it rains. You say
that you love the sun, but you find a
shadow spot when the sun shines. You
say that you love the wind, but you
close your windows when wind blows.
This is why I am afraid, you say that
you love me too.
#!/bin/sh
#
trap '' SIGINT #获取用户信号
base_dir=$(dirname $0) #获取用户当前目录
export LANG='zh_CN.UTF-8' #设置sh语言环境
python $base_dir/connect.py #调用connect.py
exit #退出
init.sh,在添加用户的时侯,就添加到了/etc/passwd里面,存放在项目目录下。
# users/views.py
CONNECTPY_PATH = os.path.join(settings.BASE_DIR, 'init.sh')
ret, msg = user_in_server.present(username=username, password=password, shell=CONNECTPY_PATH)
查看init.sh是否已添加:# vim /etc/passwd
lily:x:1003:1003::/home/lily:/root/workspace/jms/init.sh
posted on 2017-06-21 16:38 myworldworld 阅读(1234) 评论(0) 收藏 举报