python运维之paramiko
来源:互联网 发布:北洋打印机软件 编辑:程序博客网 时间:2024/04/30 01:15
paramiko是使用Python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式远程连接服务器。
1. 安装
在安装paramiko前,首先要安装PyCrypto模块。安装脚本为:
git clone https://github.com/dlitz/pycrypto.gitcd pycrypto && sudo python setup.py installcd ..git clone https://github.com/paramiko/paramiko.gitcd paramiko && sudo python setup.py installcd ..sudo rm -rf pycrypto paramiko
2. 使用paramiko
paramiko API 中最为基本的类是“paramiko.SSHClient". 它提供了与服务器连接和文件传输的最基本的接口。一个最简单的例子:
import paramikossh = paramiko.SSHClient()ssh.connect('127.0.0.1', username = 'ubuntu', password='123')它将创建一个新的SSHClient实例,然后调用“connect()”来连接本地的SSH服务,没有比这更简单的了不是吗?
HOST Keys
SSH认证另一种方法是采用密钥的方式。无论何时你使用ssh来连接一个远程的服务器,host key的信息将被自动存储在家目录下的".ssh/known_hosts"文件中。如果你通过ssh新连接一个host,将会看到以下信息:
The authenticity of host 'localhost (::1)' can't beestablished.RSA key fingerprint is 22:fb:16:3c:24:7f:60:99:4f:f4:57:d6:d1:09:9e:28.Are you sure you want to continue connecting (yes/no)?
敲入“yes”,key的信息将被保存到“known_hosts”文件中。这些密钥很重要,因为它是与主机之间的信任机制。如果key被破坏或更改,那么客户端会拒绝连接并不会通知你,而paramiko也采用相同的规则。如果在“hnown_hosts”中没有保存相关的信息,SSHClient 默认行为是拒绝连接。如果是工作在系统反反复复安装的实验环境中时,这将变得无比的烦人。设置host key的规则调用的方法叫ssh client 实例的"set_missing_host_key_policy()",它设定了你所期望的方法来管理host key.如果你像我一样懒惰,你可以用"paramiko.AutoAddPolicy()"方法来自动接收未知的key:
import paramikossh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect('127.0.0.1', username = 'ubuntu', password='123')
connect方法
connect(hostname, port=22, username=None, password=None, pkey=None,
key_filename=None,timeout=None, allow_agent=True, look_for_keys=True,
compress=False, sock=None, gss_auth=False,gss_kex=False,
gss_deleg_creds=True, gss_host=None, banner_timeout=None)
Parametershostname (str) – the server to connect to
port (int) – the server port to connect to
username (str) – the username to authenticate as (defaults to the current local username)
password (str) – a password to use for authentication or for unlocking a private key
pkey (.PKey) – an optional private key to use for authentication
key_filename (str) – the filename, or list of filenames, of optional private key(s) to try for authentication
timeout (float) – an optional timeout (in seconds) for the TCP connect
allow_agent (bool) – set to False to disable connecting to the SSH agent
look_for_keys (bool) – set to False to disable searching for discoverable private key files in ~/.ssh/
compress (bool) – set to True to turn on compression
sock (socket) – an open socket or socket-like object (such as a Channel) to use for communication to the target host
gss_auth (bool) – True if you want to use GSS-API authentication
gss_kex (bool) – Perform GSS-API Key Exchange and user authentication
gss_deleg_creds (bool) – Delegate GSS-API client credentials or not
gss_host (str) – The targets name in the kerberos database. default: hostname
banner_timeout (float) – an optional timeout (in seconds) to wait for the SSH banner to be presented.RaisesBadHostKeyException – if the server’s host key could not be verified
AuthenticationException – if authentication failed
SSHException – if there was any other error connecting or establishing an SSH session
socket.error – if a socket error occurred while connecting
port (int) – the server port to connect to
username (str) – the username to authenticate as (defaults to the current local username)
password (str) – a password to use for authentication or for unlocking a private key
pkey (.PKey) – an optional private key to use for authentication
key_filename (str) – the filename, or list of filenames, of optional private key(s) to try for authentication
timeout (float) – an optional timeout (in seconds) for the TCP connect
allow_agent (bool) – set to False to disable connecting to the SSH agent
look_for_keys (bool) – set to False to disable searching for discoverable private key files in ~/.ssh/
compress (bool) – set to True to turn on compression
sock (socket) – an open socket or socket-like object (such as a Channel) to use for communication to the target host
gss_auth (bool) – True if you want to use GSS-API authentication
gss_kex (bool) – Perform GSS-API Key Exchange and user authentication
gss_deleg_creds (bool) – Delegate GSS-API client credentials or not
gss_host (str) – The targets name in the kerberos database. default: hostname
banner_timeout (float) – an optional timeout (in seconds) to wait for the SSH banner to be presented.RaisesBadHostKeyException – if the server’s host key could not be verified
AuthenticationException – if authentication failed
SSHException – if there was any other error connecting or establishing an SSH session
socket.error – if a socket error occurred while connecting
连接到SSH服务并身份认证。host key将根据系统host key(load_system_host_keys())和本地host key(load_host_keys())来进行检查。如果在系统host key和本地host key中都没有查到相关信息,则使用未知host key策略(set_missing_host_key_policy).认证失败抛出SSHException异常。认证优先级是:
- The pkey or key_filename passed in (if any)
- Any key we can find through an SSH agent
- Any “id_rsa”, “id_dsa” or “id_ecdsa” key discoverable in ~/.ssh/
- Plain username/password auth, if a password was given
ssh.connect('10.227.129.234',username='ubuntu', compress = True, key_filename='/home/ubuntu/.ssh/test.pem',password='123')
import getpasskey_filename = '/home/ubuntu/.ssh/test.pem'try:key = paramiko.RSAKey.from_private_key_file(key_filename)except paramiko.PasswordRequiredException:password = getpass.getpass('RSA key password: ')pkey = paramiko.RSAKey.from_private_key_file(path, password)ssh = paramiko.SSHClien()ssh.connect('10.227.129.234',username='ubuntu', compress = True, pkey= pkey)这里明确指明pkey是RSA加密方式,如果是DSS加密,则将RSAKey改成DSSKey即可,可通过私钥文件第一行中的说明信息中自动判断是RSA加密还是DSS加密。
if isinstance(key_filename,str): key_file=open(key_filename,'r') key_head=key_file.readline() key_file.seek(0) if 'DSA' in key_head: keytype=paramiko.DSSKey elif 'RSA' in key_head: keytype=paramiko.RSAKey
执行命令
Execute a command on the SSH server. A new Channel is opened and the requested command is executed. The command’s input and output streams are returned as Pythonfile-like objects representing stdin, stdout, and stderr.
Parameterscommand (str) – the command to executebufsize (int) – interpreted the same way as by the built-in file()function in Python
timeout (int) – set command’s channel timeout. SeeChannel.settimeout.settimeoutReturnsthe stdin, stdout, and stderr of the executing command, as a 3-tupleRaisesSSHException:if the server fails to execute the command
现在既然已经连接好了,那么可以执行一些命令并返回命令执行结果。与其他Unix-like应用程序一样,SSH使用input、output和error来进行输入、输出和错误输出。error将被输出到标准错误输出,output输出到标准输出,如果你要将数据传回应用程序,将数据写到标准输入即可。
...>>> ssh.connect('127.0.0.1', username='jesse',password='lol')>>> stdin, stdout, stderr = ssh.exec_command("uptime")>>> type(stdin)paramiko.channel.ChannelFile>>> stdout.readlines()['13:35 up 11 days, 3:13, 4 users, load averages: 0.14 0.18 0.16\n']
这个例子中,Paramiko打开了一个新的"paramiko.Channel"实例,它代表了与远端机器连接的安全通道,Channel实例表现与python socket实例是一样的。当我们调用"exec_command()"方法时,这个Channel实例便打开,”paramiko.ChannelFile“和”file-like“实例代表了发送到和来自远端机器的数据。
从远端机器传回的ChannelFile,在标准输出和标准错误输出中使用"read()"来不断地显示内容。如果返回过多的数据而填满缓冲区,则会挂起等待程序读取。这种情况下既不是调用”readlines()“也不是"read()".如果你想在内部暂存这些数据,你可以使用”readline“来迭代。
对于系统管理的任务,同样需要对执行命令的输出结果进行分析,得益于python的强大的字符串处理能力,这简直就是小菜一碟不是吗?那就来跑跑命名吧,不过这需要一个password:
stdin, stdout, stderr = ssh.exec_command("sudo dmesg")
哦....,这里使用了sudo 命令。远程主机将在交互模式下要求我输入一个password,不用担心:
ssh.connect('127.0.0.1', username='jesse', password='lol')stdin, stdout, stderr = ssh.exec_command("sudo fdisk -l")stdin.write('lol\n')stdin.flush()data = stdout.read().splitlines()for line in data: if line: print line
#!/usr/bin/pythonimport paramikoimport cmdclass RunCommand(cmd.Cmd): """add_host Simple shell to run a command on the host """ prompt = 'ssh > ' def __init__(self): cmd.Cmd.__init__(self) self.hosts = [] self.connections = [] def do_add_host(self, args): """Add the host to the host list""" if args: self.hosts.append(args.split(',')) else: print "usage: host " def do_connect(self, args): """runConnect to all hosts in the hosts list""" for host in self.hosts: client = paramiko.SSHClient() client.set_missing_host_key_policy( paramiko.AutoAddPolicy()) client.connect(host[0], username=host[1], password=host[2]) self.connections.append(client) def do_run(self, command): """Execute this command on all hosts in the list""" if command: for host, conn in zip(self.hosts, self.connections): stdin, stdout, stderr = conn.exec_command(command) stdin.close() for line in stdout.read().splitlines(): print 'host: %s: %s' % (host[0], line) else: print "usage: run " def do_close(self, args): for conn in self.connections: conn.close()if __name__ == '__main__': RunCommand().cmdloop()输出:
ssh > add_host 127.0.0.1,jesse,lolssh > connectssh > run uptimehost: 127.0.0.1: 14:49 up 11 days, 4:27, 8 users,load averages: 0.36 0.25 0.19ssh > close这个例子仅仅是演示了伪交互式shell的概念,如果要使用它还有很多地方有待完善:更好的打印多行stdout输出,处理标准错误,添加一个结束方法,线程地处理返回的命令/数据等等。
和所有的shell一样,当需要可视化数据时,处理上限是是限制。如pssh、OSH、Fabric等工具,管理返回的数据方法都不尽相同,他们都有不同的方法来聚合来自不同主机的输出。
交互式
Start an interactive shell session on the SSH server. A new Channel is opened and connected to a pseudo-terminal using the requested terminal type and size.
Parametersterm (str) – the terminal type to emulate (for example, "vt100")width (int) – the width (in characters) of the terminal window
height (int) – the height (in characters) of the terminal window
width_pixels (int) – the width (in pixels) of the terminal window
height_pixels (int) – the height (in pixels) of the terminal windowReuturnsa new Channel connected to the remote shellRaisesSSHException:if the server fails to invoke a shell
以上都是通过paramiko模块来远程操作服务器,如果想通过paramiko模块直接用ssh协议登录到远端机器上怎么办?同样:
import paramikoimport interactive # logparamiko.util.log_to_file('/tmp/test') #create ssh connectionssh=paramiko.SSHClient()ssh.load_system_host_keys()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect('10.1.6.190',port=22,username='root',password='xxxxxx',compress=True) #create interactive shell connectionchannel=ssh.invoke_shell() #creat interactive pipinteractive.interactive_shell(channel) #close connectionchannel.close()ssh.close()
文件传输
Paramiko的文件操作时通过SFTP来实现,就像ssh客户端命令执行一样。首先就像先前一样,创建一个paramiko.SSHClient实例:
import paramikossh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect('127.0.0.1', username='jesse', password='lol')这次,我们创建了与远端机器的连接之后调用"open_sftp()"命令,"open_sftp()"返回一个"paramiko.SFTPClient"的客户端实例,支持所有sftp操作(stat, put, get, mkdir, listdir, remove, rename, symlink, unlink etc.可以用dir(ftp)来查看)。 在这个例子中,我们使用"get"操作来下载远端文件”remotefile.py“到本地系统中,并重命名为"localfaile.py"。
ftp = ssh.open_sftp()ftp.get('remotefile.py', 'localfile.py')ftp.close()写入一个文件到远端的主机中也采用同样的方法,只需将local和remote参数对调即可:
ftp = ssh.open_sftp()ftp.put( 'localfile.py','remotefile.py')ftp.close()使用paramiko提供的sftp客户端的一个优点是对诸如 stat/chmod/chown等文件属性操作的支持。你可能会很轻松地写出如"glob.glob()"这样的函数来传输某个远端文件夹下的特定文件名模式的文件,你也可以基于文件的权限、大小等搜索文件。
然而,有一点必须要注意:相比scp(secure copy)来说,sftp作为一个协议是有一些限制的。当从远端机器上下载文件时,scp可以使用Unix通配符,而sftp需要完整的文件路径,例如:
ftp.get("*.py",".")我们原本期望的是:下载所有名称为.py结束的文件到本地机器,但是sftp却不识别此方案:
>>> ftp.get("./*.py", '.')Traceback (most recent call last): File "", line 1, in File "/Library/Python/2.5/site-packages/paramiko/sftp_client.py", line 567, in get fr = self.file(remotepath, 'rb') File "/Library/Python/2.5/site-packages/paramiko/sftp_client.py", line 238, in open t, msg = self._request(CMD_OPEN, filename, imode, attrblock) File "/Library/Python/2.5/site-packages/paramiko/sftp_client.py", line 589, in _request return self._read_response(num) File "/Library/Python/2.5/site-packages/paramiko/sftp_client.py", line 636, in _read_response self._convert_status(msg) File "/Library/Python/2.5/site-packages/paramiko/sftp_client.py", line 662, in _convert_status raise IOError(errno.ENOENT, text)IOError: [Errno 2] No such file
需要注意的是,sftp的put和get函数都只支持单个文件,如果你需要传输整个目录的话,需要手动使用sftp.mkdir建立一个目录,然后自己遍历整个文件夹,并对每个文件使用put或get函数,pysftp则实现了上传下载文件夹。下面是来自stackoverflow中对paramiko上传下载文件夹问题的一个回复,他用一个SSHSession类做了一个封装:
import paramikoimport socketimport osfrom stat import S_ISDIRclass SSHSession(object): # Usage: # Detects DSA or RSA from key_file, either as a string filename or a # file object. Password auth is possible, but I will judge you for # using it. So: # ssh=SSHSession('targetserver.com','root',key_file=open('mykey.pem','r')) # ssh=SSHSession('targetserver.com','root',key_file='/home/me/mykey.pem') # ssh=SSHSession('targetserver.com','root','mypassword') # ssh.put('filename','/remote/file/destination/path') # ssh.put_all('/path/to/local/source/dir','/path/to/remote/destination') # ssh.get_all('/path/to/remote/source/dir','/path/to/local/destination') # ssh.command('echo "Command to execute"') def __init__(self,hostname,username='root',key_file=None,password=None): # # Accepts a file-like object (anything with a readlines() function) # in either dss_key or rsa_key with a private key. Since I don't # ever intend to leave a server open to a password auth. # self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((hostname,22)) self.t = paramiko.Transport(self.sock) self.t.start_client() keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) key = self.t.get_remote_server_key() # supposed to check for key in keys, but I don't much care right now to find the right notation if key_file is not None: if isinstance(key,str): key_file=open(key,'r') key_head=key_file.readline() key_file.seek(0) if 'DSA' in key_head: keytype=paramiko.DSSKey elif 'RSA' in key_head: keytype=paramiko.RSAKey else: raise Exception("Can't identify key type") pkey=keytype.from_private_key(key_file) self.t.auth_publickey(username, pkey) else: if password is not None: self.t.auth_password(username,password,fallback=False) else: raise Exception('Must supply either key_file or password') self.sftp=paramiko.SFTPClient.from_transport(self.t) def command(self,cmd): # Breaks the command by lines, sends and receives # each line and its output separately # # Returns the server response text as a string chan = self.t.open_session() chan.get_pty() chan.invoke_shell() chan.settimeout(20.0) ret='' try: ret+=chan.recv(1024) except: chan.send('\n') ret+=chan.recv(1024) for line in cmd.split('\n'): chan.send(line.strip() + '\n') ret+=chan.recv(1024) return ret def put(self,localfile,remotefile): # Copy localfile to remotefile, overwriting or creating as needed. self.sftp.put(localfile,remotefile) def put_all(self,localpath,remotepath): # recursively upload a full directory os.chdir(os.path.split(localpath)[0]) parent=os.path.split(localpath)[1] for walker in os.walk(parent): try: self.sftp.mkdir(os.path.join(remotepath,walker[0])) except: pass for file in walker[2]: self.put(os.path.join(walker[0],file),os.path.join(remotepath,walker[0],file)) def get(self,remotefile,localfile): # Copy remotefile to localfile, overwriting or creating as needed. self.sftp.get(remotefile,localfile) def sftp_walk(self,remotepath): # Kindof a stripped down version of os.walk, implemented for # sftp. Tried running it flat without the yields, but it really # chokes on big directories. path=remotepath files=[] folders=[] for f in self.sftp.listdir_attr(remotepath): if S_ISDIR(f.st_mode): folders.append(f.filename) else: files.append(f.filename) print (path,folders,files) yield path,folders,files for folder in folders: new_path=os.path.join(remotepath,folder) for x in self.sftp_walk(new_path): yield x def get_all(self,remotepath,localpath): # recursively download a full directory # Harder than it sounded at first, since paramiko won't walk # # For the record, something like this would gennerally be faster: # ssh user@host 'tar -cz /source/folder' | tar -xz self.sftp.chdir(os.path.split(remotepath)[0]) parent=os.path.split(remotepath)[1] try: os.mkdir(localpath) except: pass for walker in self.sftp_walk(parent): try: os.mkdir(os.path.join(localpath,walker[0])) except: pass for file in walker[2]: self.get(os.path.join(walker[0],file),os.path.join(localpath,walker[0],file)) def write_command(self,text,remotefile): # Writes text to remotefile, and makes remotefile executable. # This is perhaps a bit niche, but I was thinking I needed it. # For the record, I was incorrect. self.sftp.open(remotefile,'w').write(text) self.sftp.chmod(remotefile,755)
1 0
- python运维之paramiko
- 学习Python运维之paramiko模块
- 【python】python之-----paramiko
- Python运维自动化开发之Paramiko模块
- python模块之 paramiko
- python三方库之paramiko
- python之paramiko模块
- 系统运维工程师的法宝:python paramiko
- 系统运维工程师的法宝:python paramiko
- python paramiko
- paramiko python
- Python笔记之——paramiko (SSHClient)
- Python paramiko模块之SSH SFTP
- Python安装paramiko曲折之路
- python之路--paramiko实现简单主机管理
- 运维小白的python之路——paramiko
- [Python/自动化运维] 利用Paramiko模块执行批量上传/下载/执行命令/查看服务器列表
- python ssh模块paramiko
- Cocos2d-x 常用Action
- Ceilometer项目源码分析----ceilometer-agent-notification服务的初始化和启动
- 一道找朋友的问题
- Unity3D学习之(列的基本操作和约束以及泛型集合)
- 正斜杠(/)与反斜杠(\)总结
- python运维之paramiko
- erlang sys学习
- Java开发环境的安装与配置
- linux completion 笔记
- GDB调试精粹及使用实例
- ASP.NET三层架构应用总结(一)
- 分配病房
- 解决Mac下GDB提示签名错误
- 服务器架设:CentOS搭建LAMP详细教程