paramiko模块的自我封装

paramiko模块,基于SSH用于连接远程服务器并执行相关操作以及执行相关命令
执行代码:
import os
import sys

import paramiko
from paramiko.ssh_exception import NoValidConnectionsError, AuthenticationException, SSHException
import logging

#设置输出运行日志到新建my.log文件中
logging.basicConfig(filename=‘my.log’, level=logging.WARN,
format="%(asctime)s-%(filename)s-%(lineno)d- %(levelname)s: %(message)s ")
#%(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 root@172.25.254.250
    # 创建一个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 主机执行命令%s的结果: %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()
)

注意:建立以.conf结尾的文件写入需要连接的主机IP地址。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值