首页 > 系统相关 >paramiko遍历嵌套文件夹上传到linux服务器,并执行sh脚本

paramiko遍历嵌套文件夹上传到linux服务器,并执行sh脚本

时间:2023-04-28 15:56:14浏览次数:58  
标签:remote log self cmd sh file linux path paramiko

场景:由于工作原因,开发打包后都要上传包到对应linux 服务器,并执行对应shell脚本,替换包内配置文件,启动服务。换包频率过于频繁,因此需要实现一种不用打开xshell、xftp的方法,直接将包放在本地文件,双击exe运行所有操作,以节省时间,想到使用python的paramiko、pyinstaller模块实现。

功能分析:

  • 1、遍历本地嵌套文件夹获取文件
  • 2、上传到远程linux服务器
  • 3、上传文件进度条
  • 4、程序运行日志按时间存放本地
  • 5、打包成exe,双击就可以运行

代码实现:

autoChangePackage.py

import paramiko
import os
import time
import sys, math, select
import log


def get_all_files_in_local_dir(local_dir):
    """递归获取当前目录下所有文件目录"""
    all_files = []
    # 获取当前指定目录下的所有目录及文件,包含属性值
    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(get_all_files_in_local_dir(filename))
        else:
            all_files.append(filename)
    return all_files


def progressbar(cur, total):
    percent = '{:.2%}'.format(cur / total)
    sys.stdout.write('\r')
    sys.stdout.write('[%-50s] %s' % ('=' * int(math.floor(cur * 50 / total)), percent))
    sys.stdout.flush()
    if cur == total:
        sys.stdout.write('\n')


class Dossh():

    def __init__(self, ip, port, uname, passwd):
        self.ip = ip
        self.port = port
        self.uname = uname
        self.passwd = passwd
        self.sshclt = paramiko.SSHClient()
        self.sshclt.load_system_host_keys()
        self.sshclt.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.sshclt.connect(hostname=self.ip, port=self.port, username=self.uname, password=self.passwd,
                            allow_agent=False, look_for_keys=False)
        self.t = paramiko.Transport((self.ip, self.port))
        self.t.connect(username=self.uname, password=self.passwd)
        self.sftp = paramiko.SFTPClient.from_transport(self.t)

    def getssh(self):
        return self.sshclt

    def close_ssh(self):
        self.sshclt.close()
        self.sftp.close()

    def uploadfile_path(self, local_path, remote_path):
        """
        :param local_path:待上传文件夹路径
        :param remote_path:远程路径
        :return:
        """
        # 待上传目录名
        local_pathname = os.path.split(local_path)[-1]
        # 上传远程后的目录名
        real_remote_Path = remote_path + '/' + local_pathname
        ##判断是否存在,不存在则创建
        try:
            self.sftp.stat(remote_path)
        except Exception as e:
            self.sshclt.exec_command("mkdir -p %s" % remote_path)
        self.sshclt.exec_command("mkdir -p %s" % real_remote_Path)
        # 获取本地文件夹下所有文件路径
        all_files = get_all_files_in_local_dir(local_path)
        # 依次判断远程路径是否存在,不存在则创建,然后上传文件
        for file_path in all_files:
            # 统一win和linux 路径分隔符
            file_path = file_path.replace("\\", "/")
            # 用本地根文件夹名分隔本地文件路径,取得相对的文件路径
            # 必须加变量1,仅切割一次,否则会将二级目录下与一级目录名相同的文件上传错误
            off_path_name = file_path.split(local_pathname, 1)[-1]
            # 取得本地存在的嵌套文件夹层级
            abs_path = os.path.split(off_path_name)[0]
            # 生产期望的远程文件夹路径
            reward_remote_path = real_remote_Path + abs_path
            # 判断期望的远程目录是否存在,不存在则创建
            try:
                self.sftp.stat(reward_remote_path)
            except Exception as e:
                self.sshclt.exec_command("mkdir -p %s" % reward_remote_path)
            # 待上传的文件名
            abs_file = os.path.split(file_path)[1]
            # 上传后的远端路径,文件名不变
            to_remote = reward_remote_path + '/' + abs_file
            time.sleep(0.1)
            #  callback=progressbar,添加文件上传进度条
            self.sftp.put(file_path, to_remote, callback=progressbar)
            print(file_path, to_remote)

    def execute_cmd(self, cmd):
        current_cmd = "bash --login -c '%s'" % cmd
        stdin, stdout, stderr = self.sshclt.exec_command(current_cmd, get_pty=True, bufsize=1024 * 1024 * 100)
        res, err = stdout.read(), stderr.read()

        result = res if res else err
        return result.decode('utf-8')

    def do_tail(self, cmd):
        transport = self.sshclt.get_transport()
        channel = transport.open_session()
        channel.exec_command(cmd)

        while 1:
            try:
                rl, _, _ = select.select([channel], [], [], 0.0)
                if len(rl) > 0:
                    print("----------------do_tail服务开始读取日志-------------")
                    for line in self.linesplit(channel):
                        print(line)
            except (KeyboardInterrupt, SystemExit):
                print('do_tail服务日志读取异常...')
                break

    def linesplit(self, socket):
        buffer_bytes = socket.recv(4048)
        buffer_string = buffer_bytes.decode('utf-8', 'ignore')
        done = False
        while not done:
            if "\n" in buffer_string:
                (line, buffer_string) = buffer_string.split("\n", 1)
                yield line + "\n"
            else:
                more = socket.recv(4048)
                if not more:
                    done = True
                else:
                    buffer_string = buffer_string + more.decode('utf-8', 'ignore')
        if buffer_string:
            yield buffer_string


if __name__ == "__main__":

    # 自定义目录存放日志文件
    log_path = './Logs/'
    if not os.path.exists(log_path):
        os.makedirs(log_path)
    # 日志文件名按照程序运行时间设置
    log_file_name = log_path + 'log-' + time.strftime("%Y%m%d-%H%M%S", time.localtime()) + '.log'
    # 记录正常的 print 信息
    sys.stdout = log.Logger(log_file_name)
    # 记录 traceback 异常信息
    sys.stderr = log.Logger(log_file_name)
    print("==========1. 日志记录文件创建成功,见%s==========" % log_file_name)

    print("==========2. 开始连接服务器==========")
    # 服务器信息
    ma_ip = '*.*.*.*'
    ma_port = 22
    ma_user = ''
    ma_passwd = ''
    sshclent = Dossh(ma_ip, int(ma_port), ma_user, ma_passwd)
    print("==========3. 服务器连接成功==========")
    print("==========4. 开始从本地上传文件到106服务器==========")
    # 上传package包(jar+lib)
    # 本地目录,建议使用相对路径,如:'./test'
    # linux服务器目录,绝对路径,如:'/home/'
    # 会本地test目录下所有文件上传到linux服务器的/home/test
    # a、目录存在则仅覆盖文件
    # b、目录不存在则先创建目录,再上传目录下的文件
    sshclent.uploadfile_path("本地目录", 'linux服务器目录')

    # 查看linux服务器上test目录下的文件
    # cmd_ll = 'ls -l  /home/test'
    print("==========5. 文件上传成功==========")
    print("==========6. 开始执行shell脚本==========")
    cmd_shell = 'sh /home/test/test.sh'
    sshclent.execute_cmd(cmd_shell)
    time.sleep(0.1)
    # 由于换包脚本会产生执行日志,每次需要通过查看日志运行状态,来判断配置文件是否替换,服务是否启动成功
    # 但又因为execute_cmd()方法执行tail命令,控制台没有回显,因此使用do_tail()方法查看log
    print("==========7. 开始打印脚本执行日志==========")
    cmd_tailf = 'tail -F  /home/tets/test.log'
    sshclent.do_tail(cmd_tailf)
    sshclent.close_ssh()

log.py

import sys


# 控制台输出记录到文件
class Logger(object):
    def __init__(self, file_name="Default.log", stream=sys.stdout):
        self.terminal = stream
        self.log = open(file_name, "a", encoding='utf-8')

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)

    def flush(self):
        pass

打包成exe文件

1、安装pyinstaller 模块

2、pycharm编辑器控制台输入pyinstaller -F autoChangePackage.py

3、打开资源管理器,进入对应工程的dist目录下,会看见生成了autoChangePackage.exe

4、双击运行如果提示缺失配置文件,复制python安装目录下所有dll文件到exe目录,就可以成功,但一般很少遇见

注:涉及到的问题解决方法百度都有

参考文献

1、python之paramiko文件夹远程上传
2、Python 将控制台输出日志文件

标签:remote,log,self,cmd,sh,file,linux,path,paramiko
From: https://www.cnblogs.com/CloudGuest/p/17362422.html

相关文章

  • shared_ptr,unique_ptr和make_shared,make_unique
    std::shared_ptr<widget>p(newwidget());autop=std::make_shared<int>(widget); 两者的不同:1.使用make_shared的时候widget只写了一次,2.当遇到函数传参时,由于编译器执行顺序的不同,如果使用shared_ptr这种方式,当newwidget之后,后面的参数函数执行然后出现异常导致程序退出......
  • 记录一下linux-kafka命令
    使用工具:puTTY下载地址:DownloadPuTTY-afreeSSHandtelnetclientforWindowsloginas:rootroot@*******'spassword:Lastlogin:FriApr2814:54:262023from10.10.16.80[root@kafka272c41~]#cd..[root@kafka272c41/]#ls-a....autorelabelbinboot......
  • Linux常用命令
    #uname-a#查看内核/操作系统/CPU信息#head-n1/etc/issue#查看操作系统版本#cat/proc/cpuinfo#查看CPU信息#hostname#查看计算机名#lspci-tv#列出所有PCI设备#lsusb-tv#列出所有USB设备#lsmod#列出加载的内核模块#env#查看环境变量#free-m#查看......
  • Linux开机启动服务配置
     chkconfig命令可以管理在7个不同级别下是否启动某个服务,建议manchkconfig,这是一个普通但必须掌握的命令。1、使用chkconfig--list命令观察ftp的启动状态,按照你的描述,应该是在35级别启动了。(若一页显示不完,可结合catmoreless之类的命令,或者利用管道符加grep过滤出vsft......
  • Linux中将memcached注册成服务并可以随机器启动时启动服务
    网上看了很多资料大多比较繁琐,而且很多不能再最新的centos6上执行成功,最后还是自己写了一份,以供日后备用:  1.首先是写service脚本service脚本需要进入到目录/etc/init.d中,然后touchmemcached,最后vimmemcached后进行脚本编写,脚本如下:#chkconfig:3456060#!/bin/bash......
  • Install Tcpping on Linux
    Tcpping 介绍 测试网络延迟最常用方法是使用ping工具,它使用ICMP协定。在某些情况下ICMP是被防火墙阻挡,这使得Ping在这情况下是无法使用的。此时为了能够继续监控的话,就必需使用TCP/UDP的方式,TCPPING为更容易绕过普通的防火墙规则的第3层测试工具。这样的一个第3层的测试工具TC......
  • 网安等保-国产Linux操作系统银河麒麟KylinOS-V10SP3常规配置、系统优化与安全加固基线
    [点击......
  • shell脚本中if的“-e,-d,-f”
    文件表达式-efilename如果filename存在,则为真-dfilename如果filename为目录,则为真 -ffilename如果filename为常规文件,则为真-Lfilename如果filename为符号链接,则为真-rfilename如果filename可读,则为真 -wfilename如果filename可写,则为真 -xfilename如果fi......
  • Linux 实用shell脚本
    1.查看有多少远程的IP在连接本机#!/bin/bash#!/bin/bash#查看有多少远程的IP在连接本机(不管是通过ssh还是web还是ftp都统计)#使用netstat‐atn可以查看本机所有连接的状态,‐a查看所有,#-t仅显示tcp连接的信息,‐n数字格式显示#LocalAddress(第四......
  • 解决 VMware 虚拟机 Linux /dev/mapper/ubuntu--vg-ubuntu--lv 磁盘空间不足的问题
    之前在VMware安装UbuntuServer的时候磁盘分区选择了LVM,所以系统根目录默认占用磁盘大小只有4G,在安装软件时发现磁盘空间4G已经无法满足,所以需要利用LVM对磁盘进行扩容使用Docker拉取MySQL镜像时发现磁盘空间不够:nospaceleftondeviceroot@ubuntu:~#......