基于ssh用于连接远程服务器做操作:远程执行命令, 上传文件, 下载文件
import paramiko
# ssh [email protected]
# 创建一个ssh对象;
client = paramiko.SSHClient()
# 2. 解决问题:如果之前没有;连接过的ip, 会出现
# Are you sure you want to continue connecting (yes/no)? yes
# 自动选择yes
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 3. 连接服务器
client.connect(
hostname='172.25.254.1',
username='root',
password='westos'
)
# 4. 执行操作
stdin, stdout, stderr = client.exec_command('hostname')
# 5. 获取命令的执行结果;
print(stdout.read().decode('utf-8'))
# 6. 关闭连接
client.close()
from paramiko.ssh_exception import NoValidConnectionsError, AuthenticationException
def connect(cmd, hostname, user, password):
import paramiko
# ssh [email protected]
# 创建一个ssh对象;
client = paramiko.SSHClient()
# 2. 解决问题:如果之前没有;连接过的ip, 会出现
# Are you sure you want to continue connecting (yes/no)? yes
# 自动选择yes
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
# 3. 连接服务器
client.connect(
hostname=hostname,
username=user,
password=password
)
except NoValidConnectionsError as e:
return "主机%s连接失败" %(hostname)
except AuthenticationException as e:
return "主机%s密码错误" % (hostname)
except Exception as e:
return "未知错误: ", e
else:
# 4. 执行操作
stdin, stdout, stderr = client.exec_command('hostname')
# 5. 获取命令的执行结果;
res = stdout.read().decode('utf-8')
# 6. 关闭连接
client.close()
return res
if __name__ == '__main__':
with open('doc/hosts.txt') as f:
for line in f:
# 172.25.254.1:root:westos
new_line = line.strip('\n')
hostname, username, password = new_line.split(":")
res = connect('hostname', hostname, username, password )
print(hostname.center(50, '*'))
print("主机名:", res)
with open('/etc/hosts', 'a+') as f:
f.write('\n')
for i in range(100):
f.write('172.25.254.%s foundation%s.example.com \n' % (i + 1, i + 1))
目标:
1). 172.25.254.3 - host3
172.25.254.4 - host4
2). host4实现无密码连接host3?
linux中实现过程
*****host3操作: 生成公钥和私钥, 并发送私钥给host4
993 ssh-keygen
994 cd /root/.ssh/
995 ls
996 ssh-copy-id -i id_rsa.pub [email protected]
997 scp id_rsa [email protected]:/home/kiosk/.ssh/
*****host4操作:
shell命令检测是否可以成功
ssh [email protected]
代码实现
import paramiko
# ssh [email protected]
# 创建一个ssh对象;
client = paramiko.SSHClient()
# 实例化一个私钥对象
private_key = paramiko.RSAKey.from_private_key_file('/home/kiosk/.ssh/id_rsa')
# 2. 解决问题:如果之前没有;连接过的ip, 会出现
# Are you sure you want to continue connecting (yes/no)? yes
# 自动选择yes
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 3. 连接服务器
client.connect(
hostname='172.25.254.3',
username='root',
pkey= private_key ,
)
# 4. 执行操作
stdin, stdout, stderr = client.exec_command('hostname')
# 5. 获取命令的执行结果;
print(stdout.read().decode('utf-8'))
# 6. 关闭连接
client.close()
import paramiko
from paramiko import AuthenticationException, SSHException
import logging
def put(hostname, password, source_name, target_name):
# 类似于sftp命令的功能
try:
# 建立与远程主机的通道;
transport = paramiko.Transport(('172.25.254.4', 22))
# 验证用户名和密码是否正确;
transport.connect(username='root', password='Asimov')
# 根据创建并验证成功的通道, 创建sftp客户端;
sftp = paramiko.SFTPClient.from_transport(transport)
except AuthenticationException as e:
print("密码错误:", e)
except SSHException as e:
print("主机不存在:", e)
except Exception as e:
print("未知错误:", e)
else:
# 上传文件
# sftp.put('/etc/passwd', '/mnt/172.25.254.250')
# 下载文件;
sftp.get('/mnt/172.25.254.250')
finally:
# 关闭两台主机建立的通道;
transport.close()
# ssh远程连接集成了执行命令, 上传文件和下载文件的类;
import os
import sys
import paramiko
from paramiko.ssh_exception import NoValidConnectionsError, AuthenticationException, SSHException
import logging
logging.basicConfig(filename='my.log', level=logging.WARN,
format="%(asctime)s-%(filename)s-%(lineno)d- %(levelname)s: %(message)s ")
class SshRemoteHost(object):
"""
1). 实现类似lftp的功能, 只支持一部分的命令, 输入的命令不存在, 则报错;
"""
def __init__(self, host, user, pwd, cmd, port=22):
self.host = host
self.port = port
self.user = user
self.pwd = pwd
self.cmd = cmd # cmd hostname; cmd ls -l; cmd data +%F
def run(self):
# cmd hostname 类的反射机制
cmd_str = self.cmd.split()[0] # cmd
if hasattr(self, 'do_' + cmd_str): # 判断是否有do_cmd方法
getattr(self, 'do_' + cmd_str)()
else:
logging.error("目前不支持该操作.....目前支持cmd, put, get")
print("目前不支持该操作.....目前支持cmd, put, get")
def do_cmd(self):
print("正在执行命令......")
# ssh [email protected]
# 创建一个ssh对象;
client = paramiko.SSHClient()
# 2. 解决问题:如果之前没有;连接过的ip, 会出现
# Are you sure you want to continue connecting (yes/no)? yes
# 自动选择yes
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
# 3. 连接服务器
client.connect(
hostname=self.host,
username=self.user,
password=self.pwd
)
except NoValidConnectionsError as e:
logging.error("主机%s连接失败" % (self.host))
print("主机%s连接失败" % (self.host))
except AuthenticationException as e:
logging.error("主机%s密码错误" % (self.host))
print("主机%s密码错误" % (self.host))
except Exception as e:
logging.error("未知错误: ", e)
print("未知错误: ", e)
else:
# cmd hostname; cmd ls -l; cmd data +%F
# ['cmd', 'ls', '-l']
# ['ls', '-l']
# 'ls -l'
cmd = " ".join(self.cmd.split()[1:])
# 4. 执行操作
stdin, stdout, stderr = client.exec_command(cmd)
# 5. 获取命令的执行结果;
res = stdout.read().decode('utf-8')
logging.debug("%s 主机执行命令%sd的结果: %s" % (
self.host, self.cmd, res))
# 6. 关闭连接
client.close()
print(res)
def do_put(self):
"""
put /etc/passwd /tmp/hello
:return:
"""
print('正在批量上传文件.....')
# 类似于sftp命令的功能
try:
# 建立与远程主机的通道;
transport = paramiko.Transport((self.host, int(self.port)))
# 验证用户名和密码是否正确;
transport.connect(username=self.user, password=self.pwd)
# 根据创建并验证成功的通道, 创建sftp客户端;
except AuthenticationException as e:
logging.error("%s 密码错误" %(self.host),)
print("%s 密码错误:" %(self.host), e)
except SSHException as e:
logging.error("%s未知错误 :" % (self.host))
print('unknown error:', e)
else:
sftp = paramiko.SFTPClient.from_transport(transport)
# 上传文件
# put file1 file2
filenames = self.cmd.split()[1:]
if len(filenames) == 2:
# 如果执行命令: put /etc/passwd /tmp/passwd
# 目标主机上有文件: /tmp/passwd_172.25.254.1
print(filenames[0], filenames[1]+'_'+self.host)
sftp.put(filenames[0], filenames[1] + '_' + self.host)
else:
print("命令错误, 用法: put 源文件名 目标文件名")
# 关闭两台主机建立的通道;
transport.close()
def do_get(self):
print('正在批量下载文件.....')
# 类似于sftp命令的功能
try:
# 建立与远程主机的通道;
transport = paramiko.Transport((self.host, int(self.port)))
# 验证用户名和密码是否正确;
transport.connect(username=self.user, password=self.pwd)
# 根据创建并验证成功的通道, 创建sftp客户端;
except SSHException as e:
logging.error("%s未知错误 :" % (self.host), e)
# print("%s未知错误:" % (self.host), e)
print('unknown error:', e)
else:
sftp = paramiko.SFTPClient.from_transport(transport)
# 上传文件
# put file1 file2
filenames = self.cmd.split()[1:]
if len(filenames) == 2:
# 如果执行命令: put /etc/passwd /tmp/passwd
# 目标主机上有文件: /tmp/passwd_172.25.254.1
print(filenames[0], filenames[1]+'_'+self.host)
sftp.get(filenames[0], filenames[1] + '_' + self.host)
else:
print("命令错误, 用法: put 源文件名 目标文件名")
# 关闭两台主机建立的通道;
transport.close()
def main():
CONFDIR = 'conf'
# 1. 主机组显示:
print("主机组显示:".center(50, '*'))
# 如何获取conf目录中主机的分组(遍历conf目录中的所有以.conf结尾的文件,主机组名需要去掉.conf);
groups = [file.rstrip('.conf') for file in os.listdir(CONFDIR) if file.endswith('.conf')]
for group in groups: print('\t', group)
while True:
choiceGroup = input("请选择操作的主机组名称(eg: web):")
if choiceGroup not in groups:
logging.error("%s不存在" % (choiceGroup))
print("%s不存在" % (choiceGroup))
else:
break
# 2. 根据选择的主机组, 显示包含的主机IP/主机名;
# 1). 打开对应主机的配置文件, eg: conf/mysql.conf
# 2). 依次读取文件的每一行, 获取主机名;
infostr = "%s主机组包含的主机:" % (choiceGroup)
print(infostr.center(50, '*'))
hostinfos = [] # 存储需要操作的主机信息
with open('%s/%s.conf' % (CONFDIR, choiceGroup)) as f:
for line in f:
# 172.25.254.6:22:root:westos
# print(line.split(":")[0])
hostinfos.append(line.strip().split(':'))
hostname, port, user, passwd = line.strip().split(':')
print(hostname)
# 3. 批量执行脚本
print("批量执行脚本".center(50, '*'))
while True:
cmd = input(">>: ")
if cmd:
if cmd in ['exit', 'quit']:
print("执行结束, 退出中.......")
sys.exit(0)
else:
# cmd, put, get
for host in hostinfos:
hostname, port, user, passwd = host
print(hostname.center(50, '*'))
sshObj = SshRemoteHost(hostname, user, passwd, cmd, port)
sshObj.run()
if __name__ == '__main__':
main()