python-linux-获取多台远端机器指定文件并下载至本地(s**y-日志审计)

一、需求
1、将多台远端服务器上已归档的log日志文件拉取到本地服务器上;
2、日志文件名有指定前缀及日期;
3、远端服务器有空闲时段指定;
4、下载后的日志文件有特殊命名要求;
5、本地日志文件有保留期限,需定期自动清理;
*6、下载指定路径下以日期yyyymmdd格式命名的文件夹,有多重子目录及文件;

二、解决方案
1、json配置文件:将多台远端服务器的信息汇总在json文件中,如server_ip,server_dir,server_port,username,password,prefix,freetime,使用脚本循环读取执行复制下载;
2、linux的scp命令:该指令可远端拷贝文件或文件夹,对应使用python中的paramiko库
3、re模块正则匹配:筛选保留指定文件、定期清理本地文件;
*4、迭代器:遍历远端目标路径,把下级所有文件及子目录下的文件提取汇总;
*5、shutil库:shutil.rmtree删除非空文件夹;

#第一版:机器日志审计,满足需求1-5#

import json  #处理json文件
import paramiko  #链接服务器
import os
import re  #处理正则表达式
import datetime


json_dir = "/opt/jsonfile/test"  #配置json文件
local_dir = "/home/root/"  #本地存放文件目录
input_date =""  #获取日期
days=15    #文件生命周期(天)

#任务启动时间
n_time = datetime.datetime.now()

def connect(host, port=22, username='root', password='8888888'):  #链接服务器
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())  #生成ssh对象等
    try:
        ssh.connect(host, port, username, password)  #测试链接
        print('connect success')
        return ssh  #成功返回连接ssh对象
    except Exception as e:
        print('connect erro', e)
        return None  #错误返回空


def command(args, outpath):  #拼接命令
    cmd = '%s %s' % (outpath, args)
    return cmd


def exec_commands(conn, cmd):  #执行命令
    stdin, stdout, stderr = conn.exec_command(cmd)
    results = stdout.read()
    return results  #返回命令执行结果

def excutor(host, port, username, password, outpath, args):  #调用执行命令函数将结果处理返回
    conn = connect(host, port, username, password)
    if not conn:
        return None
    # exec_commands(conn,'chmod +x %s' % outpath)
    cmd = command(args, outpath)
    result = exec_commands(conn, cmd)
    result = json.dumps(result.decode(encoding="utf-8"),
                        indent=4,
                        ensure_ascii=False)
    return result


def copy_module(conn, inpath, outpath):  #使用paramiko库自带SFTP传输文件
    ftp = conn.open_sftp()
    ftp.get(inpath, outpath)  #从服务器到本地
    ftp.close()
    return outpath


def read_json():  #打开json文件并处理
    with open(json_dir, 'r+') as f:
        load_dict = json.load(f)
    return load_dict


def scan_local_file(days, local_dir):
    local_f_list = os.listdir(local_dir)
    start_day = (datetime.datetime.now() -
                 datetime.timedelta(days=days)).strftime("%Y-%m-%d")
    for i in local_f_list:
        if re.findall(r'\d{4}-\d{1,2}-\d{1,2}', i, flags=0) and (datetime.datetime.now() - datetime.datetime.strptime(
                re.findall(r'\d{4}-\d{1,2}-\d{1,2}', i, flags=0)[0],
                '%Y-%m-%d')).days > days:
            os.remove(local_dir + i)
        elif re.findall(r'\d{8}', i, flags=0) and (datetime.datetime.now() - datetime.datetime.strptime(
                re.findall(r'\d{8}', i, flags=0)[0],
                '%Y%m%d')).days > days:
            os.remove(local_dir + i)


if __name__ == '__main__':
    if input_date == "":
        less_1_now = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%Y-%m-%d")  # 1
        less_2_now = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%Y%m%d")  # 2
        # input_date=input('请输入要获取的天数格式为:xxxx-xx-xx')#2
        getday = less_1_now  # 1
        getday2 = less_2_now  # 2
    else:
        getday = input_date
        getday2 = datetime.datetime.strptime(input_date, "%Y-%m-%d").strftime("%Y%m%d")  # 匹配yyyymmdd
	
    load_dict = read_json()
    for i in load_dict:  #遍历配置
        prefix = i['prefix']
        server_ip = i['server_ip']
        server_dir = i["server_dir"]
        server_port = i["server_port"]
        username = i['username']
        password = i['password']
        freetime = i['freetime']#空闲时间 默认给 "" 或者格式为 "15:00-21:00"
        if freetime!='':
            freet_s=freetime.split('-')[0]
            freet_e=freetime.split('-')[1]
            # 范围时间
            d_time = datetime.datetime.strptime(str(datetime.datetime.now().date()) + freet_s, '%Y-%m-%d%H:%M')
            d_time1 = datetime.datetime.strptime(str(datetime.datetime.now().date()) +  freet_e, '%Y-%m-%d%H:%M')
        
            if n_time > d_time and n_time < d_time1:
                pass
            else:
                continue
			
        result = excutor(server_ip, server_port, username, password, 'ls ',
                         server_dir)
        result=result.replace('"','')
        result_lis = result.split('\\n')  #返回的结果 每个文件名之间有换行 用来分隔
        conn = connect(server_ip, server_port, username, password)
        for j in result_lis:
            if getday in j and prefix in j:  #先用正则匹配年月 再用 in 匹配前缀
                copy_module(conn, server_dir + j,local_dir + server_ip + j)
        # 增加获取文件名为yyyymmdd
        for m in result_lis:
            if getday2 in m and prefix in m:  # 先用正则匹配年月 再用 in 匹配前缀
                copy_module(conn, server_dir + m, local_dir + server_ip + '-' + m)
    scan_local_file(days, local_dir)
    print('success')
#第二版:收集sql执行日志,满足需求1-6

# -*- coding:utf-8 -*-
import paramiko as pm
import datetime as dt
import os
import stat
import re
import json
import shutil


input_date=''   # 格式为yyyymmdd
json_dir='/opt/jsonfile/server_info_new'    #配置json文件目录
local_dir='/opt/newtest/'   #配置本地目录
days=15


#任务启动时间
n_time = dt.datetime.now()

def read_json():  #打开json文件并处理
    with open(json_dir, 'r+') as f:
        load_dict = json.load(f)
    return load_dict

def getRemoteFiles(remoteDir):
    # 加载sftp服务器文件对象(根目录)
    filesAttr = sftp.listdir_attr(remoteDir)
    try:
        # foreach遍历
        for fileAttr in filesAttr:
            if stat.S_ISDIR(fileAttr.st_mode):
                        # 1.当是文件夹时
                    # 计算子文件夹在ftp服务器上的路径
                son_remoteDir = remoteDir + '/' + fileAttr.filename
                    # 生成器, 迭代调用函数自身
                yield from getRemoteFiles(son_remoteDir)
            else:
                        # 2.当是文件时
                    # 生成器, 添加"路径+文件名"到迭代器"
                yield remoteDir + '/' + fileAttr.filename
    except Exception as e:
        print('getAllFilePath exception:', e)

# 远程目录remoteDir文件下载保存到本地目录localDir
def download_file(localDir, remoteDir):

    try:
    # 实例化生成器, 获取sftp指定目录下的所有文件路径
        files = getRemoteFiles(remoteDir)
        if not (os.path.exists(localDir)) and (sftp.stat(remoteDir)):
        # 若本地目录不存在,则创建该目录
            os.makedirs(localDir)

    # foreach遍历
        for file in files:
            # 要下载的远程文件, 本地时路径+文件名
            remoteFileName = file
            # 定义下载保存到本地时的路径+文件名
            localFileName = os.path.join(localDir, file.split('/')[-1])

            try:
                # 下载文件, 本地已有同名文件则覆盖
                sftp.get(remoteFileName, localFileName)
                print('sftp服务器文件 {} 下载成功!\n该文件保存本地位置是 {} !\n'.format(
                    remoteFileName, localFileName))
            except Exception as e:
                print('%s下载出错!:\n' % (remoteFileName), e)
                # 下载失败, 关闭连接
                sftp.close()
            # 判断输入的本地目录是否存在
    except Exception as e:
        print('该日期文件不存在')
        sftp.close()
    # 下载成功, 关闭连接
    sftp.close()


# 过滤非T3.log文件
def scan_local_file(local_dir):
    try:
        local_f_list = os.listdir(local_dir)
        for i in local_f_list:
            if re.findall(r'^T3.*log$', i, flags=0) :
                pass
            else:
                os.remove(local_dir + i)
    except Exception as e:
        print('不存在T3.log文件')

# 定期清理日志文件
def scan_local_date(days, local_dir):
    local_f_list = os.listdir(local_dir)
    for i in local_f_list:
        if re.findall(r'\d{8}', i, flags=0) and (dt.datetime.now() - dt.datetime.strptime(
                re.findall(r'\d{8}', i, flags=0)[0],
                '%Y%m%d')).days > days:
            shutil.rmtree(local_dir + i) #删除非空文件夹


if __name__ == '__main__':
    if input_date =='':
        less_2_now = (dt.datetime.now() - dt.timedelta(days=1)).strftime("%Y%m%d")  # 2
        date = less_2_now
    else:
        date = input_date

    load_dict = read_json()
    for i in load_dict:  #遍历配置
        server_ip = i['server_ip']
        server_port = i["server_port"]
        username = i['username']
        password = i['password']
        remoteDir = i["server_dir"]+date+'/'
        freetime = i['freetime']  # 空闲时间 默认给 "" 或者格式为 "15:00-21:00"
        if freetime != '':
            freet_s = freetime.split('-')[0]
            freet_e = freetime.split('-')[1]
            # 范围时间
            d_time = dt.datetime.strptime(str(dt.datetime.now().date()) + freet_s, '%Y-%m-%d%H:%M')
            d_time1 = dt.datetime.strptime(str(dt.datetime.now().date()) + freet_e, '%Y-%m-%d%H:%M')

            if n_time > d_time and n_time < d_time1:
                pass
            else:
                continue
        #下载文件保存目录
        localDir=local_dir+server_ip+'-'+'sql_log'+date+'/'
        tran = pm.Transport((server_ip, server_port))
        tran.connect(username=username, password=password)
        # 获取sftp实例
        sftp = pm.SFTPClient.from_transport(tran)
        download_file(localDir, remoteDir)
        scan_local_file(localDir)
        scan_local_date(days, local_dir)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要开发一个 Python 命令行工具来升级 Sonic 系统,你需要了解以下几个方面的知识: 1. Sonic 系统升级的原理和流程 2. Python 的基本语法和命令行工具开发 3. Linux 系统的基本操作和命令 下面是一个简单的思路,可以帮助你开始开发: 1. 使用 Python 的 argparse 模块解析命令行参数,例如升级的目标设备、升级的 Sonic 版本等。 2. 使用 paramiko 模块连接到目标设备的 SSH 服务器,并执行升级命令。 3. 在升级过程中,使用 subprocess 模块在本地执行一些必要的命令,例如下载 Sonic 系统镜像、校验镜像文件等。 4. 在升级完成后,使用 paramiko 模块断开 SSH 连接。 以下是一个简单的代码示例,用于连接到目标设备并执行升级命令: ```python import paramiko import argparse # 解析命令行参数 parser = argparse.ArgumentParser(description='Upgrade Sonic system') parser.add_argument('target', help='Target device IP address') parser.add_argument('version', help='Sonic version to upgrade to') args = parser.parse_args() # 创建 SSH 客户端并连接到目标设备 client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(args.target, username='root', password='password') # 执行升级命令 stdin, stdout, stderr = client.exec_command('sonic_installer upgrade {}'.format(args.version)) for line in stdout: print(line.strip()) # 断开 SSH 连接 client.close() ``` 当然,这只是一个简单的示例,还需要结合实际场景进行改进。例如,你可能需要添加更多的错误处理和日志记录功能,以确保升级过程的可靠性和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值