python运维自动化Paramiko的实现示例
作者:秃了也弱了。
Paramiko是Python的SSH库,提供SSHClient和SFTPClient类,用于远程命令执行及文件传输,支持连接、执行、上传下载,适用于自动化部署等场景,下面就来详细介绍一下Paramiko的使用
一、Paramiko
1、安装
pip install paramiko
2、常用的类
SSHClient: 最常用的类,表示一个SSH客户端连接。
SFTPClient: 用于SFTP传输操作。
Transport: 低级别的模块,可用来实现SSH2协议。
SSHClient主要方法
connect(hostname, port=22, username=None, password=None, pkey=None): 用于连接到远程服务器。可以选择使用用户名和密码或密钥进行认证。
exec_command(command): 在远程服务器上执行指令。
open_sftp(): 返回一个SFTPClient对象,可用于文件的上传与下载。
SFTPClient主要方法
get(remotepath, localpath, callback=None): 下载远程文件。
put(localpath, remotepath, callback=None, confirm=True): 上传本地文件。
listdir(path=“.”): 列出远程目录的内容。
3、使用
(1)SSH执行远程命令
import paramiko # 创建SSH客户端 client = paramiko.SSHClient() # 自动添加未知的服务器密钥及策略 ''' AutoAddPolicy:自动添加主机名及主机密钥到本地的known_hosts,不依赖load_system_host_key的配置。即新建立ssh连接时不需要再输入yes或no进行确认。最为常用。 WarningPolicy 用于记录一个未知的主机密钥的python警告。并接受,功能上和AutoAddPolicy类似,但是会提示是新连接。 RejectPolicy 自动拒绝未知的主机名和密钥,依赖load_system_host_key的配置。此为默认选项 ''' client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接SSH服务端 ''' hostname(str类型),连接的目标主机地址; port(int类型),连接目标主机的端口,默认为22; username(str类型),校验的用户名(默认为当前的本地用户名); password(str类型),密码用于身份校验或解锁私钥; pkey(Pkey类型),私钥方式用于身份验证; key_filename(str or list(str)类型),一个文件名或文件名列表,用于私钥的身份验证; timeout(float类型),一个可选的超时时间(以秒为单位)的TCP连接; allow_agent(bool类型),设置为False时用于禁用连接到SSH代理; look_for_keys(bool类型),设置为False时用于来禁用在~/.ssh中搜索私钥文件; compress(bool类型),设置为True时打开压缩。 ''' client.connect('192.168.56.10', port=22, username='root', password='vagrant') # 执行命令 stdin, stdout, stderr = client.exec_command('ls -l') # 获取命令执行结果 result = stdout.read() print(result.decode()) # 关闭连接 client.close()
(2)SFTP上传/下载文件
import paramiko # 创建SSH客户端 client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect('192.168.56.10', port=22, username='root', password='vagrant') # 创建SFTP会话 sftp = client.open_sftp() # 上传文件 sftp.put('localfile.txt', '/remote/path/remote.txt') # 下载文件 sftp.get('/remote/path/remote.txt', 'localfile.txt') ''' mkdir,在SFTP服务端创建目录,如sftp.mkdir("/home/userdir",mode=0777),默认模式是0777(八进制),在某些系统上,mode被忽略。在使用它的地方,当前的umask值首先被屏蔽掉。 remove,删除SFTP服务端指定目录,如sftp.remove("/home/userdir")。 rename,重命名SFTP服务端文件或目录,如sftp.rename("/home/test.sh","/home/testfile.sh") stat,获取远程SFTP服务端指定文件信息,如sftp.stat("/home/testfile.sh")。 listdir,获取远程SFTP服务端指定目录列表,以Python的列表(List)形式返回,如sftp.listdir("/home")。 ''' # 关闭SFTP会话和SSH连接 sftp.close() client.close()
(3)SSH简单封装
import paramiko class SSHClient: def __init__(self, hostname, port=22, username=None, password=None, pkey=None, use_proxy=False, proxy_hostname=None, proxy_port=None, proxy_username=None, proxy_password=None, timeout=5): """ 初始化SSH客户端。 :param hostname: 主机名或IP地址 :param port: 端口号,默认是22 :param username: 用户名 :param password: 密码 :param pkey: 私钥文件对象,用于密钥认证 :param use_proxy: 是否使用代理标志 :param proxy_hostname: 代理的主机名称 :param proxy_port: 代理的端口号 :param proxy_username: 代理的用户名 :param proxy_password: 代理的密码 """ self.hostname = hostname self.port = port self.username = username self.password = password self.pkey = pkey self.use_proxy = use_proxy self.proxy_hostname = proxy_hostname self.proxy_port = proxy_port self.proxy_username = proxy_username self.proxy_password = proxy_password self.client = None self.timeout = timeout def _setup_proxy(self): """ 配置代理。 """ if self.use_proxy: proxy_ssh = paramiko.SSHClient() proxy_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) proxy_ssh.connect(hostname=self.proxy_hostname, port=self.proxy_port, username=self.proxy_username, password=self.proxy_password, timeout=self.timeout) vm_transport = proxy_ssh.get_transport() remote_address = (self.hostname, self.port) local_address = (self.proxy_hostname, self.proxy_port) vm_channel = vm_transport.open_channel("direct-tcpip", remote_address, local_address) return vm_channel else: return None def _connect(self): """ 创建SSH连接。 """ self.client = paramiko.SSHClient() self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) proxy = self._setup_proxy() self.client.connect(self.hostname, port=self.port, username=self.username, password=self.password, pkey=self.pkey, sock=proxy, timeout=self.timeout) def exec_command(self, command): """ 在远程服务器上执行命令。 :param command: 要执行的命令字符串 :return: 命令输出结果的标准输出和标准错误 """ if self.client is None: self._connect() stdin, stdout, stderr = self.client.exec_command(command) return stdout.read().decode(), stderr.read().decode() def close(self): """ 关闭SSH连接。 """ if self.client: self.client.close() self.client = None # 使用示例 if __name__ == "__main__": # 直接连接单个服务器 ''' ssh = SSHClient(hostname='192.168.56.10', port=22, username='root', password='vagrant') stdout, stderr = ssh.exec_command('ls -l') print(stdout) ssh.close() ''' # 通过代理连接 ''' ssh_with_proxy = SSHClient(hostname='hostname', port=22, username='username', password='password', use_proxy=True, proxy_hostname='proxy_hostname', proxy_port=22, proxy_username='proxy_username', proxy_password='proxy_password') stdout, stderr = ssh_with_proxy.exec_command('ls -l') print(stdout) ssh_with_proxy.close() ''' # 连接多个服务器执行多个命令 servers = { '192.168.56.10': { 'port': 22, 'username': 'root', 'password': '123' }, '192.168.56.11': { 'port': 22, 'username': 'root', 'password': '123' }, '192.168.56.12': { 'port': 22, 'username': 'root', 'password': '123' }, } commands = [ 'ls -l', 'cd xxx', ] for ip, info in servers.items(): ssh = SSHClient(hostname=ip, port=info.get('port'), username=info.get('username'), password=info.get('password')) for command in commands: stdout, stderr = ssh.exec_command(command) print(stdout) ssh.close()
(4)SFTP简单封装
#!/usr/bin/env python # coding:utf-8 from stat import * import os import paramiko class RemotLHost(object): '''封装一个远程Linux主机类,并将paramiko远程上传下载单个文件或目录的行为封装为其相应的方法''' # 通过IP, 用户名,密码,超时时间初始化一个远程Linux主机 def __init__(self, ip, username, password, timeout=30): self.ip = ip self.username = username self.password = password self.timeout = timeout # transport self.t = None # 链接失败的重试次数 self.conn_times = 3 # get单个文件 def sftp_get(self, remotefile, localfile): t = paramiko.Transport((self.ip, 22)) t.connect(username=self.username, password=self.password) sftp = paramiko.SFTPClient.from_transport(t) sftp.get(remotefile, localfile) t.close() # put单个文件 def sftp_put(self, localfile, remotefile): t = paramiko.Transport((self.ip, 22)) t.connect(username=self.username, password=self.password) sftp = paramiko.SFTPClient.from_transport(t) sftp.put(localfile, remotefile) t.close() # 获取远端linux主机上指定目录及其子目录下的所有文件 def __get_all_files_in_remote_dir(self, sftp, remote_dir): # 保存所有文件的列表 all_files = list() # 去掉路径字符串最后的字符'/',如果有的话 if remote_dir[-1] == '/': remote_dir = remote_dir[0:-1] # 获取当前指定目录下的所有目录及文件,包含属性值 files = sftp.listdir_attr(remote_dir) for x in files: # remote_dir目录中每一个文件或目录的完整路径 filename = remote_dir + '/' + x.filename print("remote file is "+ filename) # 如果是目录,则递归处理该目录,这里用到了stat库中的S_ISDIR方法,与linux中的宏的名字完全一致 if S_ISDIR(x.st_mode): all_files.extend( self.__get_all_files_in_remote_dir(sftp, filename)) else: all_files.append(filename) return all_files def sftp_get_dir(self, remote_dir, local_dir): t = paramiko.Transport((self.ip, 22)) t.connect(username=self.username, password=self.password) sftp = paramiko.SFTPClient.from_transport(t) # 获取远端linux主机上指定目录及其子目录下的所有文件 all_files = self.__get_all_files_in_remote_dir(sftp, remote_dir) # 依次get每一个文件 for x in all_files: filename = x.replace(remote_dir, "") if os.name=="nt": filename = filename.replace('/',os.sep).lstrip(os.sep) local_filename = os.path.join(local_dir, filename) filepath=os.sep.join(local_filename.split(os.sep)[0:-1]) if not os.path.exists(filepath): os.mkdir(filepath) print(u'Get <------- %s'% x) sftp.get(x, local_filename) #获取本地指定目录及其子目录下的所有文件 def __get_all_files_in_local_dir(self, local_dir): # 保存所有文件的列表 all_files = list() # 获取当前指定目录下的所有目录及文件,包含属性值 files = os.listdir(local_dir) for x in files: # local_dir目录中每一个文件或目录的完整路径 filename = os.path.join(local_dir, x) # 如果是目录,则递归处理该目录 if os.path.isdir(filename): all_files.extend(self.__get_all_files_in_local_dir(filename)) else: all_files.append(filename) return all_files def sftp_put_dir(self, local_dir, remote_dir): if remote_dir[-1] != '/': remote_dir = remote_dir + "/" t = paramiko.Transport((self.ip, 22)) t.connect(username=self.username, password=self.password) sftp = paramiko.SFTPClient.from_transport(t) for root, dirs, files in os.walk(local_dir): for filespath in files: local_file = os.path.join(root, filespath) a=local_file.replace(local_dir, '') if os.name=="nt": a = a.replace('\\','/').lstrip('/') remote_file = os.path.join(remote_dir, a) try: sftp.put(local_file,remote_file) except Exception as e: sftp.mkdir(os.path.split(remote_file)[0]) sftp.put(local_file,remote_file) print("Put %s to remote %s" % (local_file, remote_file)) for name in dirs: local_path = os.path.join(root, name) a = local_path.replace(local_dir, '') if os.name=="nt": a = a.replace('\\','/').lstrip('/') remote_path = os.path.join(remote_dir, a) try: sftp.mkdir(remote_path) print("mkdir path %s" % remote_path) except Exception as e: print(e) t.close() if __name__ == '__main__': host = RemotLHost('192.168.56.10', 'root', 'vagrant') remote_path = '/root/doc' local_path = 'D:\\test' # 将远端remote_path目录中的所有文件get到本地local_path目录 host.sftp_get_dir(remote_path, local_path) # 将本地local_path目录中的所有文件put到远端remote_path目录 local_path= 'D:\ltest' remote_path = '/root/doc2' host.sftp_put_dir(local_path, remote_path)
4、工具类
(1)自动部署
import sys import time from ssh_client import SSHClient from sftp_client import RemotLHost if __name__ == '__main__': servers = { '192.168.1.1': { 'port': 22, 'username': 'root', 'password': '' }, } for ip, info in servers.items(): print('begin============================' + ip + '============================') ssh = SSHClient(hostname=ip, port=info.get('port'), username=info.get('username'), password=info.get('password')) sftp = RemotLHost(ip=ip, username=info.get('username'), password=info.get('password')) stdout, stderr = ssh.exec_command('cd /data;sh stop.sh') print(stdout) print('stop success') time.sleep(1) remote_path = '/data/app.jar' local_path = 'E:\\app.jar' # 将远端remote_path目录中的所有文件get到本地local_path目录 sftp.sftp_put(local_path, remote_path) print('put success') time.sleep(1) stdout, stderr = ssh.exec_command('cd /data;sh start.sh') print(stdout) print('start success') time.sleep(10) stdout, stderr = ssh.exec_command('curl http://127.0.0.1:8081/check/version') print(stdout) print('end============================' + ip + '============================') ssh.close()
到此这篇关于python运维自动化Paramiko的实现示例的文章就介绍到这了,更多相关python Paramiko内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!