项目实战: CMDB自动化资产扫描(2)(项目完整实现过程)

1.项目的目录和文件

.
├── CMDBproject
│   ├── asgi.py
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-36.pyc
│   │   ├── settings.cpython-36.pyc
│   │   ├── urls.cpython-36.pyc
│   │   └── wsgi.cpython-36.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
├── hostinfo
│   ├── admin.py
│   ├── apps.py
│   ├── id_rsa
│   ├── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       ├── 0001_initial.cpython-36.pyc
│   │       └── __init__.cpython-36.pyc
│   ├── models.py
│   ├── __pycache__
│   │   ├── admin.cpython-36.pyc
│   │   ├── __init__.cpython-36.pyc
│   │   ├── models.cpython-36.pyc
│   │   ├── urls.cpython-36.pyc
│   │   ├── utils.cpython-36.pyc
│   │   └── views.cpython-36.pyc
│   ├── tests.py
│   ├── urls.py
│   ├── utils.py
│   └── views.py
├── manage.py
├── __pycache__
│   └── manage.cpython-36.pyc
└── templates
    └── hostinfo
        └── hostscan.html

2.建立Django项目 名字为CMDBproject,然后建立子应用

pip3 manage.py startApp hostinfo

将子应用添加道setting.py文件中

 (3)数据库后台admin的管理  用的是sqlite数据库

首先在modules.py中写入数据库中要导入的内容 相当于ORM

from django.db import models


class Server(models.Model):
    """服务器设备"""
    sub_asset_type_choice = (
        (0, 'PC服务器'),
        (1, '刀片机'),
        (2, '小型机'),
    )
    created_by_choice = (
        ('auto', '自动添加'),
        ('manual', '手工录入'),
    )
    # Create your models here.
    sub_asset_type = models.SmallIntegerField(choices=sub_asset_type_choice,
                                              default=0, verbose_name="服务器类型")
    created_by = models.CharField(choices=created_by_choice, max_length=32,
                                  default='auto', verbose_name="添加方式")
    hosted_on = models.ForeignKey('self', related_name='hosted_on_server',
                                  blank=True, null=True, verbose_name="宿主机",
                                  on_delete=models.CASCADE)  # 虚拟机专用字段
    IP = models.CharField('IP地址', max_length=30, default='')
    MAC = models.CharField('Mac地址', max_length=200, default='')
    model = models.CharField(max_length=128, null=True, blank=True,
                             verbose_name='服务器型号')
    hostname = models.CharField(max_length=128, null=True, blank=True,
                                verbose_name="主机名")
    os_type = models.CharField('操作系统类型', max_length=64, blank=True,
                               null=True)
    os_distribution = models.CharField('发行商', max_length=64, blank=True,
                                       null=True)
    os_release = models.CharField('操作系统版本', max_length=64, blank=True,
                                  null=True)
def __str__(self):
    return '%s-%s' % (self.id, self.hostname)
class Meta:
    verbose_name = '服务器'
    verbose_name_plural = "服务器"

 根据ORM(对象关系映射)将面向对象形式的模型进行迁移, 生成中间代码

python manage.py makemigrations

将生成的迁移文件转成SQL语句并执行SQL语句, 创建对应的数据库及数据库表

python manage.py migrate   

查看sqlite数据库  注意需要提前建立该数据库

创建后台管理的超级用户

python manage.py createsuperuser

运行项目python manage.py runserver 查看管理 

此时看不到添加的数据库  需要在admin.py文件中加入

from django.contrib import admin
from .models import  Server
admin.site.register(Server)

 

(4)前台的管理

需求:
    1. 用户访问http://ip/hostscan/返回一个html页面表单[填写的是需要扫描的主机IP或者网段,用逗号分隔开](开始扫描按钮)

    2. 用户填写好网段/IP之后,将填写的信息提交给服务器路由处理(/hostscan/)POST方法;

第一步: 配置路由 

配置总的路由:

#/root/PycharmProjects/CMDBproject/CMDBproject/urls.py



from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('hostinfo.urls')),
]

配置子路由:

#/root/PycharmProjects/CMDBproject/hostinfo/urls.py
from django.contrib import admin
from django.urls import path
from hostinfo import views

urlpatterns = [
    path('hostscan/', views.hostscan,name='hostscan'),
]

 第二步:配置视图函数   由于该项目设计的功能较多 在写视图函数时在hostinfo目录下建立一个新的utlis.py 文件

# utils.py  
import nmap
import telnetlib
import re
import paramiko



def get_active_hosts(host='172.25.254.20'):
    """Get IP is active or get network how many server is active"""
    # 实例化对象, portScanner()类用于实现对指定主机进行端口扫描
    nm = nmap.PortScanner()
    # 以指定方式扫描指定主机或网段的指定端口
    result = nm.scan(hosts=host, arguments='-n -sP')
    #print("扫描结果: ", result)
    # 返回nmap扫描的主机清单,格式为列表类型
    #print("主机清单: ", nm.all_hosts())
    return nm.all_hosts()


def is_ssh_up(host='172.25.254.20', port=22, timeout=5):
    try:
        # 实例化对象
        tn = telnetlib.Telnet(host=host, port=port, timeout=timeout)
        # read_until读取直到遇到了换行符或超时秒数。默认返回bytes类型,通过decode方法解码为字符 串。
        tn_result = tn.read_until(b"\n", timeout=timeout).decode('utf-8')
        # 通过正则匹配且忽略大小写, 寻找是否ssh服务开启。
        ssh_result = re.search(pattern=r'ssh', string=tn_result, flags=re.I)
    except Exception as e:
        print("%s ssh is down, Beacuse %s" % (host, str(e)))
        return False
    else:
        # 如果能匹配到内容, 说明ssh服务开启, 是Linux服务器.
        return True if ssh_result else False


def login_ssh_key(hostname='172.25.254.20', port=22, username='root',
                  private_key='/root/PycharmProjects/CMDBproject/hostinfo/id_rsa', command='df -h'):
    # 0. Read private key file
    pkey = paramiko.RSAKey.from_private_key_file(private_key)
    # 1. Instance a Object
    client = paramiko.SSHClient()
    # 5.(tips) When first ssh connect server, have a question (Yes|no),
    # So we want auto answer
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # 2. connect Server
    client.connect(hostname, port, username, pkey=pkey)
    # 3. execute command
    stdin, stdout, stderr = client.exec_command(command)
    # 4. print stdout result
    return stdout.read().decode('utf-8')

if __name__ == '__main__':
    # print(get_active_hosts())
    # print(is_ssh_up(host='192.168.1.20'))
    print(login_ssh_key())
#views.py
from django.shortcuts import render
from django.http import HttpResponse

from hostinfo.models import Server
from hostinfo.utils import get_active_hosts, is_ssh_up, login_ssh_key
from CMDBproject.settings import commands

# Create your views here.
"""
需求:
    1. 用户访问http://ip/hostscan/返回一个html页面
    表单[填写的是需要扫描的主机IP或者网段,用逗号分隔开](开始扫描按钮)

    2. 用户填写好网段/IP之后,将填写的信息提交给服务器路由处理(/hostscan/)
    POST方法;
"""


def hostscan(request):
    # print(request.method)
    if request.method == 'POST':
        # how to get form post data
        # {'scanhosts': '172.25.254.250,172.25.254.0/24'}
        # print(request.POST)
        """
        # 1. Get Dictionary key
        request.POST.get('scanhosts')

        # 2. split ip and network
        request.POST.get('scanhosts')[0].split(',')
        **
        s = "172.25.254.250,172.25.34.0/24"
        s.split(',')
        Out[3]: ['172.25.254.250', '172.25.34.0/24']
        """
        # ['172.25.254.250', '172.25.34.0/24']
        scanhosts = request.POST.get('scanhosts').split(',')
        servers = []

        for scanhost in scanhosts:
            print("正在扫描%s......" % (scanhost))
            # 获取所有可以ping通的主机IP
            active_hosts = get_active_hosts(scanhost)
            for host in active_hosts:
                if is_ssh_up(host):
                    # Instance Server(ORM)===> MySQL
                    # If ip exists ,How to manage?
                    server = Server()
                    server.IP = host
                    """
                    commands = {
                    'hostname': 'hostname',
                    'os_type': 'uname',
                    'os_distribution': 'dmidecode -s system-manufacturer',
                    'os_release': 'cat /etc/redhat-release',
                    'MAC': 'cat /sys/class/net/`[^vtlsb]`*/address',
                }
                    """
                    for command_name, command in commands.items():
                        # command_name="os_type", command="uname"
                        result = login_ssh_key(hostname=host, command=command)
                        # set server object attribute
                        setattr(server, command_name, result)
                    # save to mysql
                    server.save()
                    # Now Scan host info
                    servers.append(server)
        return render(request, "hostinfo/hostscan.html", {'servers': servers})
    return render(request, 'hostinfo/hostscan.html')

 前端文件的显示  在templates目录底下新建html文件

实现的一些command需要在settings文件中加入

<!DOCTYPE html>
<html>
<head>
    <title>Scan Host</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 引入 Bootstrap -->
    <!-- 新 Bootstrap 核心 CSS 文件 -->
    <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <!-- HTML5 Shiv 和 Respond.js 用于让 IE8 支持 HTML5元素和媒体查询 -->
</head>
<body>
<nav class="navbar navbar-inverse" role="navigation">
    <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" href="/">CMDB</a>
        </div>
        <div>
            <ul class="nav navbar-nav">
                <li class="active"><a href="/hostscan/">Scanhost</a></li>
            </ul>
        </div>
    </div>
</nav>
<div class="container">
    <div class="row">
        <div class="col-sm-6 col-sm-offset-3">
            <h1>Scan Host</h1>
            <form action="/hostscan/" method="post">
                {% csrf_token %}
                <input type="text" name="scanhosts"
                       width="800px"
                       placeholder="eg:172.25.254.0/24,192.168.0.0/24">
                <input type="submit" value="submit">
            </form>

            <br/>
            {% if servers %}
                <table class="table table-striped table-hover">
                    <tr>
                        <td>ID</td>
                        <td>IP</td>
                        <td>hostname</td>
                        <td>os_distribution</td>
                    </tr>
                    {% for server in servers %}
                        <tr>
                            <td>{{ server.id }}</td>
                            <td>{{ server.IP }}</td>
                            <td>{{ server.hostname }}</td>
                            <td>{{ server.os_distribution }}</td>
                        </tr>
                    {% endfor %}
                </table>
            {% endif %}

        </div>
    </div>
</div>
<!-- jQuery (Bootstrap 的 JavaScript 插件需要引入 jQuery) -->
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
</body>
</html>

最后的测试效果

输入要监控的资产主机ip

 详细的代码文件参看 GitHub·    https://github.com/Summerskq/CMDBproject

猜你喜欢

转载自blog.csdn.net/weixin_43215948/article/details/107737636