运维前线:一线运维专家的运维方法、技巧与实践2.5 使用Django快速构建CMDB系统

2.5 使用Django快速构建CMDB系统


2.5.1 Django介绍

Django是一个免费的、开源的Web框架,由Python语言编写,由于其是在一个快节奏的新闻编译室环境中开发出来的,因此它的设计目的是让普通开发者的工作变得简单。Django遵循模型-视图-控制器(MVC)框架模式,目前由一个非盈利的独立组织的软件基金会(DSF)维持。

Django鼓励快速开发和干净实用的设计。Django可以更容易更快速地构建更好的Web应用程序。它是由经验丰富的开发人员来创建的,省去了Web开发的很多麻烦,因此你可以专注地开发应用程序而不需要去白费力气地重复工作。

Django目前已经被运维圈广泛使用,本文在此不会详细介绍Django的基础知识,有兴趣的朋友可以去Django官网查看更为详细的介绍,同时也有Django中文文档可供学习。

2.5.2 Django安装

Django的安装分为4个步骤,下面以Django 1.7.1、CentOS 6.5 x86_64为例进行讲解,详细步骤如下。

1.?安装Python 2.7.x

用CentOS 7以下版本的朋友需要将Python升级到2.7.x以上,Django对Python版本存在依赖,具体如图2-7所示。

编译步骤如下:

# yum install -y zlib-dev openssl-devel sqlite-devel bzip2-devel

# wget http://www.python.org/ftp/python/2.7.6/Python-2.7.6.tgz

# tar zxf Python-2.7.6.tgz

# cd Python-2.7.6

# ./configure --prefix=/usr/local

# make && make altinstall

(1)安装easy_install工具,操作命令如下:

$ wget https://bootstrap.pypa.io/ez_setup.py -O -| python

(2)安装Django,使用easy_install来安装,安装的版本为1.7.1,具体命令如下:

$ easy_install django==1.7.1

(3)测试Django的安装,操作命令如下:

$ easy_install django==1.7.1

$ django-admin –version

1.7.1

2.?MySQL安装

本文推荐使用yum命令进行安装,并设置MySQL root密码,创建cmdbtest数据库,具体安装步骤如下:

$ yum -y install mysql mysql-server

$ mysql_install_db --user=mysql

$ /etc/init.d/mysqld start

$ mysqladmin -u root password 'cmdbtest'

$ mysql -u root -pcmdbtest -e 'create database if not exists cmdbtest'

2.5.3 Django常用命令

完成Django的安装后,可以通过如下命令快速熟悉Django的操作,以便快速创建一个CMDB App,如果你对如下这些Django命令很熟悉,可以直接跳过。

(1)新建一个django-project:

$ django-admin startproject project-name

(2)新建App:

$ django-admin startapp app-name

(3)同步数据库:

$ python manage.py syncdb

(4)启动Django服务器:

$ python manage.py runserver

(5)Django Shell调试:

$ python manage.py shell

(6)帮助:

$ django-admin --help

$ python manage.py --help

2.5.4 Django的配置

1.?环境准备

笔者准备了两台测试机器用来进行代码测试,测试机器的环境信息分别如下。

(1)服务端机器信息:

IP: 10.20.122.100

Role: puppet server + cmdb

System OS: CentOS release 6.5 x86_64

Python version: 2.7.8 Django version: 1.7.1

Mysql version: 5.1.73

(2)客户端机器信息:

IP: 10.20.122.111

Role: puppet agent

System OS: CentOS release 6.5 x86_64

2.?软件安装

前几节已经对所需要的环境进行了安装,在这里我们再回顾一下:

(1)master安装Puppet Server。

(2)master安装Python。

(3)master安装MySQL。

(4)master安装Django。

(5)master安装项目依赖的Python模块。

(6)Agent安装Puppet Agent。

3.?创建CMDB项目

创建CMDB项目的同时,在这个项目中创建一个CMDB App,登录10.20.122.100,运行如下命令。

(1)创建一个Project:

$ django-admin startproject myproject

(2)进入myproject目录:

$ cd myproject

(3)创建一个CMDB App:

$ django-admin startapp cmdb

(4)创建一个存放静态文件和模板的目录:

$ mkdir static templates

运行成功后使用11命令就可以看到如图2-8所示的目录结构。

4.?配置CMDB项目信息

在图2-8中我们可以在myproject目录下看到settings.py的全局配置文件,Django在运行时会默认先加载此配置文件,因此我们需要先对它进行定义,需要配置如下6个地方,操作步骤具体如下。

(1)修改数据库设置:

DATABASES = {

'default': { 'ENGINE': 'django.db.backends.mysql',

'NAME': 'cmdbtest',

'HOST': 'localhost',

'USER': 'root',

'PASSWORD': 'cmdbtest',

'PORT': '3306',

'OPTIONS': {'init_command': 'SET storage_engine=INNODB', 'charset': 'utf8', }

} }

(2)设置App,把我们新建的CMDB App加到末尾,代码如下:

NSTALLED_APPS = ('django.contrib.admin',

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.messages',

'django.contrib.staticfiles', 'cmdb',

)

(3)设置静态文件存放目录:

STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static/'), )

(4)设置模板文件存放目录:

TEMPLATE_DIRS = [ os.path.join(BASE_DIR, 'templates'), ]

(5)设置登录URL:

LOGIN_URL = '/cmdb/login/'

(6)设置其他参数,可以根据自己的需求进行设置:

TEMPLATE_CONTEXT_PROCESSORS = ( 'django.core.context_processors.static', 'cmdb.context_processors.menu', "django.contrib.auth.context_processors.auth", "django.core.context_processors.request",

) CMDB_VERSION = '1.0' CMDB_NAME = u'测试 CMDB' LOGIN_REDIRECT_URL = '/home/'

到此为止基础环境已经准备完毕,接下来需要设计数据库,并定义好视图。

5.?数据表设计

Django遵循MVC设计,其中M(模型)就是数据库模型,也就是App中的models.py文件的设置,Django自带数据库的ORM(Object Relational Mapping)架构,这使得我们不用再需要学习复杂的数据库操作,只需要通过定义models即可。下面是我设置的最简单的CMDB数据结构:

# 指定解析器为Python

# !/usr/bin/env python

# 指定字符编码为utf8

# encoding:utf8

# 从django.db中导入models模块

from django.db import models

# 导入User模块

from django.contrib.auth.models import User

# Create your models here.

# 定义一个Server_Group类,从models.Model中继承,这里就是所谓的数据表结构

class Server_Group(models.Model):

    # 定义主机组名称字段

    name = models.CharField(u'主机组', max_length=255, unique=True)

    # 关联的项目字段,这里是关联一个外键

    project = models.ForeignKey("Project", verbose_name='项目名称')

    # 备注字段

    memo = models.CharField(u'备注', max_length=255, blank=True)

    # unicode返回值

    def __unicode__(self):

        # 返回的格式

        return '%s-%s' % (self.project.name, self.name)

 

    # 定义Meta属性

    class Meta:

        # 数据库中的表名

        db_table = 'server_group'

        # 存储的时候需要确认组合键是唯一的

        unique_together = (("name", "project"),)

 

# 定义一个IDC类,主要存储IDC信息,数据表结构有2个字段

class IDC(models.Model):

    # 定义IDC的名称字段

    name = models.CharField(u'IDC名称', max_length=255, unique=True)

    memo = models.CharField(u'备注', max_length=255, blank=True)

 

    def __unicode__(self):

        return self.name

 

    class Meta:

        db_table = 'idc'

 

# 定义一个Project类,主要存储项目信息,数据表结构有2个字段

class Project(models.Model):

    name = models.CharField(u'项目名称', max_length=255, unique=True)

    memo = models.CharField(u'备注', max_length=255, blank=True)

 

    def __unicode__(self):

        return self.name

 

    class Meta:

        db_table = 'project'

 

# 定义一个Server_Role类,主要存储服务器角色信息,数据表结构有3个字段

class Server_Role(models.Model):

    name = models.CharField(u'角色', max_length=255)

    # 关联Server_Group,也就是服务器组

    group = models.ForeignKey("Server_Group", verbose_name='项目组')

    memo = models.CharField(u'备注', max_length=255, blank=True)

 

    def __unicode__(self):

        return '%s-%s-%s' % (self.group.project.name, self.group.name, self.name)

 

    class Meta:

        # 设置数据库表名

        db_table = 'server_role'

        # 存储的时候需要确认组合键是唯一的

        unique_together = (("name", "group"),)

 

 

# CMDB核心数据表结构,用来存储服务器系统信息

class Server_Device(models.Model):

    # 服务器状态选择,具体的字段存储数据为0~3的int数字

    SERVER_STATUS = (

        (0, u'下线'),

        (1, u'在线'),

        (2, u'待上线'),

        (3, u'测试'),

    )

    # 定义一个名称字段,若blank没有设置则默认为False,不能为空,且unique=True必须唯一

    name = models.CharField(u'主机名称', max_length=100, unique=True)

    # 定义SN编号字段, blank=True,可以为空

    sn = models.CharField(u'SN号', max_length=200, blank=True)

    # 公网IP字段,可以为空

    public_ip = models.CharField(u'外网IP', max_length=200, blank=True)

    # 私网IP字段,可以为空

    private_ip = models.CharField(u'内网IP', max_length=200, blank=True)

    # 定义MAC地址字段

    mac = models.CharField(u'MAC地址', max_length=200, blank=True)

    # 定义操作系统字段

    os = models.CharField(u'操作系统', max_length=200, blank=True)

   # 定义磁盘信息字段

    disk = models.CharField(u'磁盘', max_length=200, blank=True)

    # 定义内存信息字段

    mem = models.CharField(u'内存', max_length=200, blank=True)

    # 定义CPU信息字段

    cpu = models.CharField(u'CPU', max_length=200, blank=True)

    # 关联IDC信息

    idc = models.ForeignKey(IDC, max_length=255, blank=True, null=True, verbose_

    name='机房名称')

    # 定义一个多对多字段,一台服务器可以对应多个角色

    role = models.ManyToManyField("Server_Role", verbose_name='角色', blank=True)

    # 机器状态,默认都为在线状态

    status = models.SmallIntegerField(verbose_name='机器状态', choices=SERVER_STATUS,

    default=1)

    # 管理用户信息

    admin = models.ForeignKey('auth.User', verbose_name='管理员', null=True, blank=True)

    # 定义备注字段

    memo = models.CharField(u'备注', max_length=200, blank=True)

 

    def __unicode__(self):

        return self.name

 

    class Meta:

        db_table = 'server_device'

初始化数据库,同时设置登录所需要的username和password,命令如下:

$ python manage.py syncdb

Operations to perform:

Apply all migrations: admin, contenttypes, auth, sessions

Running migrations:

Applying contenttypes.0001_initial... OK

Applying auth.0001_initial... OK

Applying admin.0001_initial... OK

Applying sessions.0001_initial... OK

You have installed Django's auth system, and don't have any superusers defined.

Would you like to create one now? (yes/no): yes

# 这里输入用户名

Username (leave blank to use 'root'): admin

Email address:

# 这里输入密码

Password:

# 重复输入密码

Password (again):

Superuser created successfully.

在命令行登录数据库,并查看数据库信息,就能看到如图2-9所示的内容,说明数据库已创建成功。

6.?视图设置

上文中我们已经成功设置了Django的M(Models,模型),下面我们来设置V(View,视图),如下代码是一个登出页面和一个home页面的View:

# encoding:utf8

# Create your views here.

# 导入需要使用的模块

from django.template import RequestContext

from django.shortcuts import render_to_response

from django.contrib.auth.decorators import login_required

from django.contrib.auth.views import logout_then_login

# 判断用户是否登录

@login_required

# 登出时的调用

def logout_view(request):

    return logout_then_login(request)

# 判断用户是否登录

@login_required

# 登录后调用home页所展示的页面,template为home.html

def home(request):

    return render_to_response('home.html', locals(), context_instance=RequestCo

    ntext(request))

 

URL设置(这里直接使用了Django自带的login函数,所以不需要自己写login view):

# 设置字符编码

# encoding:utf8

# 从urls中导入patterns、include、url模块

from django.conf.urls import patterns, include, url

# 从contrib中导入admin模块

from django.contrib import admin

# 从http中导入HttpResponseRedirect模块

from django.http import HttpResponseRedirect

 

# 设置前端访问的URL对应的后端视图

urlpatterns = patterns('',

                     # url什么参数都不带时,直接重定向到login

                       url(r'^$', lambda x: HttpResponseRedirect('/login/')),

                     # 登出对应的视图为cmdb.views.logout_view

                         url(r'^logout/$','cmdb.views.logout_view', name='cmdb_logout'),

                     # 登录对应的view为django.contrib.auth.views.login,对应的

                           template为login.html

                       url(r'^login/$','django.contrib.auth.views.login', {'template_

                       name': 'login.html'},

                           name='cmdb_login'),

                     # home页面,对应的view为cmdb.views.home

                       url(r'^home/$', 'cmdb.views.home', name='home'),

)

通过如上定义,现在就启动Django服务,登录后即可看到如图2-10所示的界面。代码已托管至Github网站https://github.com/oysterclub/open-cmdb,有兴趣的朋友可以去复制下来查看、修改或使用。下面就来展示一下登录界面的效果图(注,前端框架为bootstrap)。

利用python manage.py syncdb命令输入的用户名和密码登录。登录后的页面为home空白页(见图2-11),具体如下(home空白页主要是为了以后做导向流页面或数据图表展示页面,这里先留空):

 

图2-11 系统登录后的界面

7.?使用Python程序获取Facts数据

通过如上定义,我们已经完成了视图、数据表结构的定义。而数据的来源既可以通过添加,也可以通过Facter工具来获取。下面我们就来讲讲如何自动获取Agent机器的系统数据(如果想要充分了解Facter工具,可以参考阅读《Puppet实战》的第9章“Facter介绍”)。Facter工具会在Puppet Agent与Puppet Master通信的时候把获取到的Agent主机系统信息和自己定义的Facts信息汇报给Puppet Master,生成一个hostname.yaml格式的文件,文件存放在/var/lib/puppet/yaml/facts目录下,文件的格式如图2-12所示,其中的values数据:domain、ipaddress、macaddress等正是构建CMDB所需要的系统数据,因此我们可以通过一个Python程序来处理这些数据,并录入MySQL中,最终通过Django来实现前端展示。因此一个最简单的CMDB系统就构建完成了。

 

图2-12 Facter上报至Puppet Master后的yaml部分信息

我们先来具体看一下facter_message.py程序(Python程序处理Facter数据),完整代码如下:

#!/usr/bin/env python

# encoding: utf8

__authors__ = ['liuyu', 'chenlijun']

__version__ = 1.0

__date__ = '2015-09-06 14:58:23'

__licence__ = 'GPL licence'

 

# 导入模块

import yaml

import os

# IPy主要用来判断IP类型,IPy.IP('ip').iptype()

import IPy

 

# yaml文件目录

yaml_dir = '/var/lib/puppet/yaml/facts'

 

# 结果集,结果集的格式{'cmdb_agent':()}

all_host_facter_message = {}

 

# 结果列表

result_list = ['name',

               'SN',

               'public_ip',

               'private_ip',

               'mac',

               'os',

               'disk',

               'mem',

               'cpu',

               'idc',

               'role',

               'status',

               'admin',

               'memo']

 

# db对应的Facter字段,需要获取其他的字段时可以一一对应

list_field = {'name': 'fqdn',

              'public_ip': 'ipaddress__interfaces',

              'private_ip': 'ipaddress__interfaces',

              'mac': 'macaddress__interfaces',

              'os': ['operatingsystem', 'operatingsystemrelease', 'hardwaremodel'],

              'disk': 'blockdevice__blockdevices',

              'mem': 'memorysize',

              'cpu': ['processorcount', 'processor0']}

 

# ruby objectobjectconstruct

def construct_ruby_object(loader, suffix, node):

    return loader.construct_yaml_map(node)

 

def construct_ruby_sym(loader, node):

    return loader.construct_yaml_str(node)

 

# 读取数据

def yaml_file_handle(filename):

    stream = open(filename)

    mydata = yaml.load(stream)

    return mydata

 

# 获取IP的类型

def get_ip_type(ip):

    try:

        return IPy.IP(ip).iptype().lower()

    except Exception, e:

        print e

 

# 处理单个Agent的数据

def handle_facter_message(data):

    # 定义一个结果字典,字段和db一样,处理完的结果和db中的一样

    result_dict = {}

    # 对结果进行处理

    for db_field in result_list:

        # 定义一个字段结果字符

        value = ''

        # result_list中的字段是否存在于我们需要的Facter取值列表中,如果存在

        if db_field in list_field:

            facter_field = list_field[db_field]

            # 先判断facter_field的类型,然后进行处理

            if type(facter_field) == type([]):

                for tag in facter_field:

                    if data.get(tag):

                        value += data[tag] + ' '

            else:

                # 由于disk、IP等需要进一步处理,所以用了一个__来分隔,然后再进行处理

                field_tmp = facter_field.split("__")

                if len(field_tmp) == 2:

                    if db_field == 'disk':

                        for tag in data[field_tmp[1]].split(","):

                            # 对磁盘进行处理, 由于磁盘的字段为blockdevice_type_size,

                                  所以需要单独进行处理

                            f = field_tmp[0] + '_' + tag + '_' + 'size'

                            if data.get(f):

                                # 去除sr0 tag的字段

                                if tag != 'sr0':

                                    # 结果字符串

                                    value += tag + ':' + str(int(data[f]) / 1024 /

                                    1024 / 1024) + 'G' + ' '

                    # 对外网IP进行处理

                    elif db_field == 'public_ip':

                        for tag in data[field_tmp[1]].split(","):

                            f = field_tmp[0] + '_' + tag

                            if data.get(f):

                                # 去除lo tag的字段

                                if tag != 'lo':

                                    if get_ip_type(data[f]) == 'public':

                                        # 结果字符串

                                        value += data[f] + ' '

                    # 对内外IP进行处理

                    elif db_field == 'private_ip':

                        for tag in data[field_tmp[1]].split(","):

                            f = field_tmp[0] + '_' + tag

                            if data.get(f):

                                # 去除lo tag的字段

                                if tag != 'lo':

                                    if get_ip_type(data[f]) == 'private':

                                        # 结果字符串

                                        value += data[f] + ' '

                    else:

                        # 其他的字段直接就处理了

                        for tag in data[field_tmp[1]].split(","):

                            f = field_tmp[0] + '_' + tag

                            if data.get(f):

                                # 去除lo tag的字段

                                if tag != 'lo':

                                    # 结果字符串

                                    value += tag + ':' + data[f] + ' '

                else:

                    if data.get(facter_field):

                        # 结果字符串

                        value = data[facter_field]

            # 将结果添加到result列表中

            result_dict[db_field] = value.strip()

        # 如果不存在

        else:

            result_dict[db_field] = ''

    # 返回结果字典

    return result_dict

 

# 定义获取facter的函数

def get_all_host_facter_message():

    # 由于Puppet的yaml文件是Ruby格式的,因此需要进行转换

    yaml.add_multi_constructor(u"!ruby/object:", construct_ruby_object)

    yaml.add_constructor(u"!ruby/sym", construct_ruby_sym)

    # 获取所有有Facter信息的主机文件名称

    for dirpath, dirnames, filenames in os.walk(yaml_dir):

        # 只需要处理yaml目录下以yaml结尾的文件

        if dirpath == yaml_dir:

            for file in filenames:

                file_name, file_ext = os.path.splitext(file)

                if file_ext == '.yaml':

                    host_yaml_path = yaml_dir + '/' + file

                    # 得到yaml文件的内容, 字典形式

                    host_yaml_result_dict = yaml_file_handle(host_yaml_path)

                    # 对单个Agent的数据进行处理

                    if host_yaml_result_dict:

                        # 由于有key为facts,所以可以直接查找facts key的值

                        if host_yaml_result_dict.has_key('facts'):

                            data_dict = host_yaml_result_dict['facts']['values']

                        # 没有的就直接取

                        else:

                            data_dict = host_yaml_result_dict['values']

 

                    # 现在就可以对data进行处理,获取我们所需要的数据了

                    result_dict = handle_facter_message(data_dict)

                    all_host_facter_message[file_name] = result_dict

    #返回我们最终的数据结果集

    return all_host_facter_message

以上程序可以过滤Facter中我们想要得到的Agent数据,运行facter_message.py程序,结果输出如下:

$ python facter_message.py

{'puppetclient.domain.com':

{'status': '',

'name': 'puppetclient.domain.com',

'mem': '1.83 GB',

'memo': '',

'idc': '',

'public_ip': '',

'admin': '',

'mac': 'eth0:00:1A:4A:25:E2:12 eth1:00:1A:4A:25:E2:13',

'role': '',

'private_ip': '10.20.122.111',

'disk': 'vda:20G vdb:30G',

'os': 'CentOS 6.5 x86_64',

'cpu': '2 Intel Core 2 Duo P9xxx (Penryn Class Core 2)',

'SN': ''}

}

到这里,我们能够看到facter_message.py得到的数据字段和models.py中数据结构的字段正好一样,下一步我们就可以直接将facter_message.py的数据导入到数据库中了,具体程序如下:

# 检测用户是否登录

@login_required

# 定义一个views,用来处理导入信息

def import_data(request, model):

    # 导入计数器

    import_num = 0

    # 查看model是否存在于定义的模板中

    if model in BASE_ADMIN:

        # 获取tag名称

        tag_name = BASE_ADMIN[model]['name']

        # 获取model名称

        model_name = BASE_ADMIN[model]['model']

        # 这里只处理server_device的导入信息

        if model == 'server_device':

            server_device_data = get_all_host_facter_message()

            # 进行数据入库处理

            for hostname, facter_message in server_device_data.items():

                # 主机名处理,判断facter_message中name key是否有值,

                if facter_message['name']:

                    # 如果有值,name就使用该值

                    name = facter_message['name']

                # 如果没有这个值

                else:

                    # 就使用hostname

                    name = hostname

                # 对于IDC信息、User信息、项目角色信息的处理都需要自己去写Facter插件,不

                       写的都为空,然后进行处理

                # IDC关联处理,如果facter_message中的idc key有值

                if facter_message['idc']:

                    # idc_name就为该值

                    idc_name = facter_message['idc']

                    # 同时处理该IDC信息是否存在于IDC表中,如果有则取出ID

                    if IDC.objects.filter(name=idc_name):

                        idc_id = IDC.objects.get(name=idc_name).id

                    # 如果没有,则进行保存,然后取出ID

                    else:

                        idc_sql = IDC(name=idc_name)

                        try:

                            idc_sql.save()

                            # 取出ID

                            idc_id = IDC.objects.get(name=idc_name).id

                        except Exception, e:

                            return e

                # 如果idc key没有值,则为None

                else:

                    idc_id = None

                # 管理员信息关联处理,如果用户存在则关联,不存在则跳过

                if facter_message['admin']:

                    admin_name = facter_message['admin']

                    # 如果用户存在User表中则取ID,若没有则为空

                    if User.objects.filter(username=admin_name):

                        user_id = User.objects.get(username=admin_name).id

                    else:

                        user_id = None

                # 没有就为空

                else:

                    user_id = None

                # 这里还有一个角色多对多关系的处理,由于这里没有定义机器角色,因此此处不处理

                      角色信息

                # 判断主机是否存在于server_device表中,如果不存在则添加

                if not model_name.objects.filter(name=name):

                    import_sql = model_name(name=name,

                                            sn=facter_message['sn'],

                                            public_ip=facter_message['public_ip'],

                                            private_ip=facter_message['private_ip'],

                                            mac=facter_message['mac'],

                                            idc=idc_id,

                                            os=facter_message['os'],

                                            disk=facter_message['disk'],

                                            mem=facter_message['mem'],

                                            cpu=facter_message['cpu'],

                                            admin=user_id,

                                            memo=facter_message['memo'],

                    )

                    try:

                        # 保存

                        import_sql.save()

                    except Exception, e:

                        return e

                # 如果有了,则查询数据,若信息不对则更新

                elif not model_name.objects.filter(name=name,

                    sn=facter_message['sn'],

                    public_ip=facter_message['public_ip'],

                    private_ip=facter_message['private_ip'],

                    mac=facter_message['mac'],

                    os=facter_message['os'],

                    disk=facter_message['disk'],

                    mem=facter_message['mem'],

                    cpu=facter_message['cpu'],

                    memo=facter_message['memo']):

                    try:

                        # 更新数据库

                            model_name.objects.filter(name=name).update(sn=

                            facter_message['sn'],

                            public_ip=facter_message['public_ip'],

                            private_ip=facter_message['private_ip'],

                            mac=facter_message['mac'],

                            os=facter_message['os'],

                            disk=facter_message['disk'],

                            mem=facter_message['mem'],

                            cpu=facter_message['cpu'],

                            memo=facter_message['memo'],

                        )

                    except Exception, e:

                        return e

                # 如果有了,且信息ok,则跳过

                else:

                    continue

        return HttpResponseRedirect('/cmdb/%s/show/' % model)

 

    return render_to_response('all_data_show.html', locals(), context_instance=RequestContext(request))

重新登录CMDB之后的页面,有一个导入主机的按钮,点击导入主机按钮,就可以自动导入通过Facter获取的Agent主机信息了,如图2-13所示。

我们还可以通过添加的方式来维护CMDB的内容,到目前为止我们已经完成了使用Python和Puppet来构建一个小型的、简单的CMDB系统。

CMDB是需要我们定期进行维护和更新的,因此它还需要提供历史查看、API等更实用的功能,为此在2.6节中我们将介绍一下Django提供的几个好用的功能模块。

 

图2-13 信息导入界面

上一篇:《云数据中心构建实战:核心技术、运维管理、安全与高可用》——1.3 数据中心分类与分级


下一篇:LeetCode: Longest Consecutive Sequence [128]