paramiko类Fabric主机管理

环境:Linux python3.5

要求:
类 Fabric 主机管理程序开发:
1. 运行程序列出主机组或者主机列表
2. 选择指定主机或主机组
3. 选择让主机或者主机组执行命令或者向其传输文件(上传/下载)
4. 充分使用多线程或多进程
5. 不同主机的用户名密码、端口可以不同

结构:
bin-----|
start.py ......启动目录,需配置主机列表
core----|
main.py ......主目录
conf----|
config.py ......配置目录
system.ini ......配置文件
file ......上传下载默认目录

用法:
先在system.ini中配置主机IP组
选择主机IP,输入用户名密码,登陆
选择需要执行命令或者传输文件
传输文件默认目录为file目录

bin:
#!/usr/bin/env python
# -*-coding:utf-8-*-
# Author:zh
import os
import sys
import threading
PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(PATH)
from core import main
from conf import config

if __name__ == '__main__':
    conf = config.Configuration()
    ip_list = eval(conf.get_config()[0][1])
    thread = threading.Thread(target=main.main, args=(ip_list,))
    thread.start()
start.py

core:

#!/usr/bin/env python
# -*-coding:utf-8-*-
# Author:zh

import paramiko
import os
PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))+os.sep+"file"+os.sep


class Fabric(object):
    '''这个类用来初始化SFTPClient和SSHClient'''
    def __init__(self, hostname, port, username, password):
        self.hostname = hostname
        self.port = port
        self.username = username
        self.password = password
        self.transport = paramiko.Transport((self.hostname, self.port))
        self.transport.connect(username=self.username, password=self.password)

    def command(self, cmd_input):
        # 执行命令
        ssh = paramiko.SSHClient()
        ssh._transport = self.transport
        stdin, stdout, stderr = ssh.exec_command(cmd_input)
        res, err = stdout.read(), stderr.read()
        result = res if res else err
        print(result.decode())

    def sftp(self, data):
        # 上传下载入口
        self.sftp = paramiko.SFTPClient.from_transport(self.transport)
        data_split = data.split()
        sign = data_split[0]
        if len(data_split) == 2:
            file_path = data_split[1]
            if file_path.rfind("/") == -1:
                file_name = file_path
            else:
                file_name = file_path[file_path.rfind("/")+1:]
            local_path = PATH+file_name
        elif len(data_split) == 3:
            if sign == "get":
                local_path = data_split[2]
                file_path = data_split[1]
            if sign == "put":
                file_path = data_split[2]
                local_path = data_split[1]
        else:
            local_path = ''
            file_path = ''
        if hasattr(self, sign):
            func = getattr(self, sign)
            try:
                func(file_path, local_path)
            except Exception as e:
                print("错误 %s" % e)
        else:
            print("输入错误")
            self.help()

    def get(self, *args):
        # 下载
        file_path = args[0]
        local_path = args[1]
        self.sftp.get(file_path, local_path)

    def put(self, *args):
        # 上传
        file_path = args[0]
        local_path = args[1]
        self.sftp.put(local_path, file_path)

    @staticmethod
    def help(self):
        # 展示帮助信息
        show = '''
        get path local_path ......从path下下载到本地目录
        put local_path path ......从本地上传到path目录下
        '''
        print(show)

    def close(self):
        # 关闭连接
        self.transport.close()


def logon():
    # 登陆,输入端口,用户名,密码
    while True:
        port = input("请输入端口:")
        if not port:
            continue
        if not port.isdigit():
            print("请输入正确的端口")
            continue
        port = int(port)
        name = input("请输入用户名:")
        if not name:
            continue
        pwd = input("请输入密码:")
        if not pwd:
            continue
        return [port, name, pwd]


def show(show_list):
    '''展示列表给用户选择,并返回选择信息'''
    while True:
        for value, comment in enumerate(show_list):
            print("%s. %s" % (value+1, comment))
        choose = input("请选择:")
        if not choose:
            continue
        if choose == "exit":
            exit()
        try:
            choose = int(choose)-1
            show_list[choose]
            return choose
        except (ValueError, IndexError) as e:
            print("输入错误:%s ,请重新输入" % e)
            continue


def main(ip_list):
    # 主方法,程序入口
    ip_list = ip_list
    choose_ip = show(ip_list)
    value_list = logon()
    port = value_list[0]
    name = value_list[1]
    pwd = value_list[2]
    while True:
        action_list = ["执行命令", "上传下载"]
        choose_action = show(action_list)
        ssh = Fabric(ip_list[choose_ip], port, name, pwd)
        if choose_action == 0:
            func = ssh.command
        else:
            func = ssh.sftp
        while True:
            cmd_input = input("-->")
            if not cmd_input:
                continue
            if cmd_input == 'b':
                ssh.close()
                break
            if cmd_input == 'exit':
                exit()
            func(cmd_input)
main.py

conf:

#!/usr/bin/env python
# -*-coding:utf-8-*-
# _author_=zh
import os
import configparser
PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


class Configuration(object):
    def __init__(self):
        self.config = configparser.ConfigParser()
        self.name = PATH+os.sep+"conf"+os.sep+"system.ini"

    def init_config(self):
        # 初始化配置文件,ip :客户端IP,port:客户端端口
        if not os.path.exists(self.name):
            self.config["config"] = {"ip_list":['192.168.200.128', '192.168.200.129', '192.168.200.130']}
            self.config.write(open(self.name, "w", encoding="utf-8", ))

    def get_config(self, head="config"):
        '''
        获取配置文件数据
        :param head: 配置文件的section,默认取初始化文件config的数据
        :return:返回head中的所有数据(列表)
        '''
        self.init_config() # 取文件数据之前生成配置文件
        self.config.read(self.name, encoding="utf-8")
        if self.config.has_section(head):
            section=self.config.sections()
            return self.config.items(section[0])
config.py

 



posted @ 2018-01-02 18:32  zhuh  阅读(199)  评论(0编辑  收藏  举报