自动化运维与python项目实战: Linux服务器主机监控脚本(2)用difflib增添文件差异性对比项目

目录

difflib的使用

difflib简介

配置文件内容差异对比的实现

文件一致性检查的实现

将文件差异性对比加入项目

 编写子路由文件:

编写视图函数

编写加密文件

编写模板文件

运行效果


 

difflib的使用

difflib简介

difflib python 的标准库模块,无需安装。用于对比文本之间的差异。并且支持输出可读性比较强
HTML 文档,类似 Linux 系统的 diff 命令。
 
应用场景 : 代码和配置文件差异对比。
 
准备工作 :
1. 两个不同时间备份的 Nginx 配置文件
2. Pycharm 集成化编程工具
 
 
 
 

配置文件内容差异对比的实现

实现代码及详解:

import difflib

# 1. 需要分析两个配置文件的不同,需要读取文件的内容
# 如果是windows系统, 目录路径的分隔符是\, 一定要转义
# 如果是Linux系统, 目录路径的分隔符是/, 不需要转义
filename1 = '/root/PycharmProjects/Devops/input/nginx_backup_20200725.conf'
filename2 = '/root/PycharmProjects/Devops/input/nginx_backup_20200726.conf'
with open(filename1) as f:
    # readlines读取文件的所有内容,以列表的数据格式存储,每个元素是一行内容。
    content1 = f.readlines()
with open(filename2) as f:
    content2 = f.readlines()

# 2. 通过difflib模块对文件内容进行对比
# # 2-1). we instantiate a Differ object
diff = difflib.Differ()
# # 2-2). Finally, we compare the two: result = list(d.compare(text1, text2))
results = diff.compare(content1, content2)
# for result in results:
#     # result是字符串, result.strip方法是删除字符串前面和后面的空格(广义的空格\n, \t,' ')
    #     print(result.strip())
# 2-3). 以更美观的方式对文件差异性对比进行展示
hdiff = difflib.HtmlDiff()
result = hdiff.make_file(content1, content2)  # 会禅城一个html字符串
# 将产生的字符串存储到html文件中
# 文件存储的方法1:python 04_配置文件差异性对比.py  > output/diff.html
# print(result)
# 文件存储的方法2: 通过python方法写入文件
filename='/root/PycharmProjects/Devops/output/diff.html'
with open(filename,'w')as f:
    f.write(result)
    print("写入html文件[%s]成功" % (filename))

执行效果:用浏览器打开输出文件diff.html

 

文件一致性检查的实现

需求: 当进行代码审计或者校验备份结果时,往往需要检查原始与目标文件一致性

代码实现及详解:

import difflib
import  hashlib
"""
集成文件差异性对比的功能到Sysinfo项目中: 
"""
def find_file_different(filename1, filename2, output_filename):
    # 1. 需要分析两个配置文件的不同,需要读取文件的内容
    # 如果是windows系统, 目录路径的分隔符是\, 一定要转义
    # 如果是Linux系统, 目录路径的分隔符是/, 不需要转义
    with open(filename1) as f:
        # readlines读取文件的所有内容,以列表的数据格式存储,每个元素是一行内容。
        content1 = f.readlines()
    with open(filename2) as f:
        content2 = f.readlines()

    # 2. 通过difflib模块对文件内容进行对比
    # # 2-1). we instantiate a Differ object
    # diff = difflib.Differ()
    # # 2-2). Finally, we compare the two: result = list(d.compare(text1, text2))
    # results = diff.compare(content1, content2)
    # for result in results:
    #     # result是字符串, result.strip方法是删除字符串前面和后面的空格(广义的空格\n, \t,' ')
    #     print(result.strip())
    # 2-3). 以更美观的方式对文件差异性对比进行展示
    hdiff = difflib.HtmlDiff()
    result = hdiff.make_file(content1, content2)  # 会禅城一个html字符串
    # 将产生的字符串存储到html文件中
    # 文件存储的方法1:python 04_配置文件差异性对比.py  > output/diff.html
    # print(result)
    # 文件存储的方法2: 通过python方法写入文件
    with open(output_filename, 'w') as f:
        f.write(result)
        print("写入html文件[%s]成功" % (output_filename))

def test_fun1():
    # 我的代码是Windows系统
    filename1 = 'input/nginx_backup_20200725.conf'
    filename2 = 'input/nginx_backup_20200726.conf'
    output_filename = 'output/diff.html'
    find_file_different(filename1, filename2, output_filename)

def is_same_file(filename1, filename2):
    """
    1. hashlib模块
    Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。
    2. 摘要算法
    摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。
    3. 摘要算法的有效性:
    摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,
    但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。
    """
    with open(filename1) as f:
        # 读取文件的所有内容,以列表的数据格式存储,每个元素是一行内容。
        content1 = f.read()
        # 第一种摘要算法的实现方式
        # 注意: python3中所有的字符串默认是unicode编码格式,如果需要utf-8编码的时候,使用encode方法进行编码操作
        """
        ASCII编码:只能存储英文信息(字母,数字,符号),一个字符占用一个字节,1字节=8位 2^8-1
        Unicode编码:是可以支持多种语言,一个字符占用2个字节,2字节=16位, 2^16-1
        utf-8编码:如果是中文,占用3个字节,如果是英文占用一个字节,从而节省空间
        GBK 2312编码:针对于汉字的编码格式
        """
        md1 = hashlib.md5()
        md1.update(content1.encode('utf-8'))
        hex_content1 = md1.hexdigest()
    with open(filename2) as f:
        content2 = f.read()
        # 第二种摘要算法的实现方式
        md1 = hashlib.md5(content2.encode('utf-8'))
        hex_content2 = md1.hexdigest()
    # print("1: ", hex_content1)
    # print("2: ", hex_content2)
    return  hex_content1 == hex_content2


"""
1. if __name__=="__main__"是什么含义?
__name__ 是当前模块名,
1). 当模块被直接运行时模块名为 __main__ 。这句话的意思就是,当模块被直接运行时,if 以下代码块将被运行。
2). 当模块是被导入时,代码块不被运行。
"""
if __name__ == '__main__':
    filename1 = 'input/nginx_backup_20200725.conf'
    filename2 = 'input/nginx_backup_20200726.conf'
    output_filename = 'output/diff.html'
    if is_same_file(filename1, filename2):
        print("[*] 文件内容一致, 不需要进行差异性对比")
    else:
        print("[*] 文件内容不一致, 差异性对比结果请查看: ", output_filename)
        find_file_different(filename1, filename2, output_filename)




运行结果:

 

将文件差异性对比加入项目

 编写子路由文件:

from django.urls import path, include
from . import  views
urlpatterns = [
    # 子路由配置,有对应的视图函数.
    path('', views.index, name='index'),
    path('disk/',views.disk,name='disk'),
    path('users/',views.users,name='users'),
    path('diff/',views.diff,name='diff')
]

 

编写视图函数

import difflib

from django.shortcuts import render
from django.http import HttpResponse
import os
import platform
from datetime import datetime
import time
import psutil

# Create your views here.
# 需求1: 用户访问http://127.0.0.1:8000,返回主机的详情信息
from host.tools import get_md5


def index(request):
    try:
        # 如果是Linux系统,执行下面内容
        # os.uname在windows系统中不能执行
        system_info = os.uname()
        node = system_info.nodename
        system = system_info.sysname
    except Exception as e:
        # 如果是Windows系统,执行下面内容
        system_info = platform.uname()
        node = system_info.node
        system = system_info.system

    boot_time = psutil.boot_time()
    boot_time = datetime.fromtimestamp(boot_time)
    now_time = datetime.fromtimestamp(time.time())
    info = {
        'node':node,
        'system': system,
        'kernal_name': system,
        'release': system_info.release,
        'version': system_info.version,
        'machine': system_info.machine,
        'now_time': now_time,
        'boot_time': boot_time,
        'boot_delta': now_time-boot_time


    }
    return render(request,'host/index.html',{'info': info})

# 需求2:用户访问http://ip/disk/,返回磁盘分区的详细信息
def disk(request):
    # 获取系统所有的磁盘分区
    parts = psutil.disk_partitions()
    disks = []
    # 依次遍历获取每个分区的详细信息
    for part in parts:
        # 查看当前磁盘分区的使用率
        usage = psutil.disk_usage(part.device)
        # 每个分区的详细信息存储到列表中
        disk = {
            'device':part.device,
            'mountpoint':part.mountpoint,
            'fstype':part.fstype,
            'opts':part.opts,
            'total':usage.total,
            'percent':usage.percent,
        }
        disks.append(disk)
    # 返回html页面信息
    return render(request,'host/disk.html',{'disks':disks})

# 需求3:用户访问http://ip/users/,返回当前登录用户的详细信息
def users(request):
    all_users = []
    users = psutil.users()
    for user in users:
        one_user = {
            'name':user.name,
            'host':user.host,
            'started':datetime.fromtimestamp(user.started)
        }
        all_users.append(one_user)
    return render(request,'host/users.html',{'users':all_users})

# 需求4:用户访问http://ip/, diff/,返回html页面,可以让用户上传文件
def diff(request):
    """
    HTTP请求方法有哪些?
        - GET: 一般情况下Get方法用于获取html页面内容
        - POST: 一般情况下用于上传数据信息和上传文件信息
    """
    print("客户端请求的方法: ", request.method)
    if request.method == 'POST':
        # 获取用户前端上传的文件
        files = request.FILES
        # 获取第一个和第二个文件对象, 通过read读取文件的内容
        content1 = files.get('filename1').read()
        content2 = files.get('filename2').read()
        # 对于文件进行差异性对比
        # 判断md5加密是否相同, 如果相同,则文件一致,否则,显示差异性对比
        # 如何自动导入模块? Alt+Enter
        if get_md5(content1) == get_md5(content2):
            return HttpResponse("文件内容一致")
        else:
            hdiff = difflib.HtmlDiff()
            content1 = content1.decode('utf-8').splitlines()
            content2 = content2.decode('utf-8').splitlines()
            # print(content1)
            # make_file传入的是列表类型的文件内容
            result = hdiff.make_file(content1, content2)  # 会生成一个html字符串
            return HttpResponse(result)
    return render(request, 'host/diff.html')

 

 

编写加密文件

#/host/tools.py

import hashlib

def get_md5(content):
    """对于字符串进行md5加密"""
    md1 = hashlib.md5(content)
    return md1.hexdigest()

 

编写模板文件

#templates/host/diff.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>配置文件差异性对比</title>
    {#  导入Bootstrap帮我们设置好的CSS样式和JS的动效   #}
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
{% include 'host/nav.html' %}
<div class="container">
    <div class="row">
        <div class="col-sm-6 col-sm-offset-3">
            <h1>配置文件差异性对比</h1>
            {#form表单需要指定的信息: 1). 提交的方式method=post 2). 提交给哪一个路由处理? /diff/对应的视图函数是diff函数#}
            {# form表单上传文件时,一定要设置 enctype="multipart/form-data"         #}
            <form role="form" action="/diff/" method="post" enctype="multipart/form-data">
                {% csrf_token %}
                <div class="form-group">
                    <label for="inputfile">第一个配置文件:</label>
                    <input type="file" id="inputfile" name="filename1">
                </div>
                <div class="form-group">
                    <label for="inputfile">第二个配置文件:</label>
                    <input type="file" id="inputfile" name="filename2">
                </div>
                <button type="submit" class="btn btn-success">上传文件</button>
            </form>
            {#<form action="#">#}
            {#    第一个配置文件: <input type="file" name="filename1"><br/>#}
            {#    第二个配置文件: <input type="file" name="filename2"><br/>#}
            {#    <input type="submit" value="上传">#}
            {#</form>#}
        </div>
    </div>
</div>


</body>
</html>

 

 

运行效果

至此,本项目告一段落!下个项目CMDB见!

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值