一、 前言
1.1 簡介
CMDB(Configuration Management Database)配置管理數據庫,是所有運維工具的數據基礎。70%~80%的IT相關問題與環境的變更有着直接的關系。實施變更管理的難點和重點並不是工具,而是流程。即通過一個自動化的、可重復的流程管理變更,使得當變更發生的時候,有一個標准化的流程去執行,能夠預測到這個變更對整個系統管理產生的影響,並對這些影響進行評估和控制。而變更管理流程自動化的實現關鍵就是CMDB。
1.2 功能
應該知道包含這幾種功能:整合、調和、同步、映射和可視化
- 用戶管理,記錄測試,開發,運維人員的用戶表
- 業務線管理,需要記錄業務的詳情
- 項目管理,指定此項目用屬於哪條業務線,以及項目詳情
- 應用管理,指定此應用的開發人員,屬於哪個項目,和代碼地址,部署目錄,部署集群,依賴的應用,軟件等信息
- 主機管理,包括雲主機,物理機,主機屬於哪個集群,運行着哪些軟件,主機管理員,連接哪些網絡設備,雲主機的資源池,存儲等相關信息
- 主機變更管理,主機的一些信息變更,例如管理員,所屬集群等信息更改,連接的網絡變更等
- 網絡設備管理,主要記錄網絡設備的詳細信息,及網絡設備連接的上級設備
- IP管理,IP屬於哪個主機,哪個網段, 是否被占用等
二、 四種實現方式
2.1 Agent方式
- 流程分析

優缺點分析:
優點: 速度快,使用於服務器多的大型公司
缺點: 需要為每一台服務器都部署一個Agent程序,機器過多時耗費的人力成本大
2.2 ssh方式(基於paramiko模塊)
- 流程分析

優缺點分析:
優點: 不需要為每一台服務器都部署一個Agent程序,適用於服務器較少的情況
缺點: 需要登錄,執行速度慢,需要部署一台中控機
import paramiko #創建ssh對象 ssh = paramiko.SSHClient() # 連接服務器 ssh.connect(hostname='localhost', port=22, username='root', password='123') # 執行命令 stdin, stdout, stderr= ssh.exec_command('ifconfig') # 拿到命令的執行結果 res = stdout.read() # 關閉連接 ssh.close()
2.3 saltstack方式
- 流程分析

優缺點分析:
優點: 速度快,開發成本低
缺點: 需要依賴於第三方工具,需要部署中控機
- saltstack安裝與配置
1. 安裝
master端
# 安裝salt-master
yum install salt-master
# 修改配置文件:/etc/salt/master
interface: 0.0.0.0 # 表示Master的IP
# 啟動
service salt-master start
slave端:
# 安裝salt-minion
yum install salt-minion
# 修改配置文件 /etc/salt/minion
master: 10.211.55.4 # master的地址
或
master:
- 10.211.55.4
- 10.211.55.5
random_master: True
id: c2.salt.com # 客戶端在salt-master中顯示的唯一ID
# 啟動
service salt-minion start
2. 授權
"""
salt-key -L # 查看已授權和未授權的slave
salt-key -a salve_id # 接受指定id的salve
salt-key -r salve_id # 拒絕指定id的salve
salt-key -d salve_id # 刪除指定id的salve
"""
3. 執行
# 在master服務器上對salve進行遠程操作
salt 'c2.salt.com' cmd.run 'ifconfig'
# 基於API的方式
import salt.client
local = salt.client.LocalClient()
result = local.cmd('c2.salt.com', 'cmd.run', ['ifconfig'])
2.4 Puppet方式(了解)
- 通過RPC消息隊列將執行的結果返回給用戶!年代久遠,作為了解,不做敘述
三、 表結構設計
首先,創建一個Django項目,由於我們的數據表既與后台管理有關又與API有關,所以我們在設計表結構時又新創建了兩個APP(backend,warehouse),這樣設計的好處就是相互獨立又方便三者間的關聯。

然后我們在warehouse的models中創建數據庫模型
from django.db import models # Create your models here. class UserInfo(models.Model): ''' 用戶信息 ''' name = models.CharField(verbose_name='姓名', max_length=32) age = models.CharField(max_length=11, verbose_name='年齡') gender = models.CharField(max_length=11, verbose_name='性別') email = models.EmailField(verbose_name='郵箱') phone = models.CharField(verbose_name='手機', max_length=32) class Meta: verbose_name_plural = '用戶表' def __str__(self): return self.name class UserGroup(models.Model): ''' 用戶組 ''' name = models.CharField(max_length=32, verbose_name='組名') users = models.ManyToManyField('UserInfo', verbose_name='組成員') class Meta: verbose_name_plural = '用戶組表' def __str__(self): return self.name class BusinessUnit(models.Model): ''' 業務線 ''' name = models.CharField(max_length=32) contact = models.ForeignKey('UserGroup', verbose_name='業務聯系人') manager = models.ForeignKey('UserGroup', verbose_name='管理人員', related_name='aaa') class Meta: verbose_name_plural = '業務線表' def __str__(self): return self.name class Idc(models.Model): ''' 機房信息 ''' name = models.CharField(max_length=32, verbose_name='機房名') floor = models.IntegerField(default=10, verbose_name='樓層') class Meta: verbose_name_plural = '機房信息表' def __str__(self): return self.name class Tag(models.Model): ''' 資產標簽 ''' name = models.CharField('標簽', max_length=32, unique=True) class Meta: verbose_name_plural = "標簽表" def __str__(self): return self.name class Asset(models.Model): ''' 資產信息表 ''' type_choices = ( (1, '服務器'), (2, '交換機'), (3, '防火牆') ) status_choices = ( (1, '上架'), (2, '在線'), (3, '離線'), (4, '下架') ) device_type_id = models.IntegerField(choices=type_choices, default=1) device_status_id = models.IntegerField(choices=status_choices, default=1) cabinet_num = models.CharField(max_length=32, verbose_name='機櫃號', null=True, blank=True) cabinet_order = models.CharField(max_length=32, verbose_name='機櫃序號', null=True, blank=True) idc = models.ForeignKey('Idc', verbose_name='IDC機房', null=True, blank=True) business_unit = models.ForeignKey('BusinessUnit', verbose_name='屬於的業務線', null=True, blank=True) tag = models.ManyToManyField('Tag') latest_date = models.DateField(null=True) create_at = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = "資產表" def __str__(self): return "%s-%s-%s" % (self.idc.name, self.cabinet_num, self.cabinet_order) class NetworkDevice(models.Model): ''' 網絡設備 ''' asset = models.OneToOneField('Asset') management_ip = models.CharField(max_length=64, verbose_name='管理ip', null=True, blank=True) vlan_ip = models.CharField(max_length=64, verbose_name='VLANIP', null=True, blank=True) intranet_ip = models.CharField(max_length=128, verbose_name='內網IP', null=True, blank=True) sn = models.CharField(max_length=64, verbose_name='sn號', null=True, blank=True) manufacture = models.CharField(max_length=128, verbose_name='制造商', null=True, blank=True) model = models.CharField(max_length=128, verbose_name='型號', null=True, blank=True) port_num = models.SmallIntegerField(verbose_name='端口數量', null=True, blank=True) device_detail = models.CharField(max_length=255, verbose_name='設置詳細配置', null=True, blank=True) class Meta: verbose_name_plural = "網絡設備表" class Server(models.Model): ''' 服務器 ''' asset = models.OneToOneField('Asset') hostname = models.CharField(max_length=32, unique=True) sn = models.CharField(max_length=64, db_index=True) manufacturer = models.CharField(max_length=64, verbose_name='制造商', null=True, blank=True) model = models.CharField(max_length=64, verbose_name='型號', blank=True, null=True) manage_ip = models.GenericIPAddressField(verbose_name='管理IP', null=True, blank=True) os_platform = models.CharField(max_length=32, verbose_name='系統', null=True, blank=True) os_version = models.CharField(max_length=32, verbose_name='系統版本', null=True, blank=True) cpu_count = models.IntegerField(verbose_name='CPU數量', null=True, blank=True) cpu_physical = models.IntegerField(verbose_name='CPU物理數量', null=True, blank=True) cpu_model = models.CharField(max_length=128, verbose_name='CPU型號', null=True, blank=True) create_time = models.DateTimeField(auto_now_add=True, blank=True) class Meta: verbose_name_plural = "服務器表" def __str__(self): return self.hostname class Disk(models.Model): ''' 硬盤信息 ''' slot = models.CharField(max_length=12, verbose_name='插槽位') model = models.CharField(max_length=32, verbose_name='磁盤型號') capacity = models.CharField(max_length=32, verbose_name='磁盤容量GB') pd_type = models.CharField(max_length=32, verbose_name='磁盤類型') server = models.ForeignKey('Server', related_name='disk') class Meta: verbose_name_plural = "硬盤表" def __str__(self): return self.slot class Nic(models.Model): ''' 網卡信息 ''' name = models.CharField(max_length=32, verbose_name='網卡名稱') hwaddr = models.CharField(max_length=64, verbose_name='網卡MAC地址') netmask = models.CharField(max_length=64) ipaddrs = models.CharField(max_length=256, verbose_name='IP地址') up = models.BooleanField(default=False) server = models.ForeignKey('Server', related_name='nic') class Meta: verbose_name_plural = "網卡表" def __str__(self): return self.name class Memory(models.Model): ''' 內存信息 ''' slot = models.CharField(max_length=12, verbose_name='插槽位') model = models.CharField(max_length=64, verbose_name='內存型號') manufacturer = models.CharField(max_length=32, verbose_name='制造商', null=True, blank=True) capacity = models.FloatField(verbose_name='容量', null=True, blank=True) sn = models.CharField(max_length=64, verbose_name='sn號', null=True, blank=True) speed = models.CharField(max_length=16, verbose_name='速度', null=True, blank=True) class Meta: verbose_name_plural = "內存表" def __str__(self): return self.slot class AssetRecord(models.Model): ''' 資產變更記錄表 ''' asset = models.ForeignKey('Asset') content = models.TextField(null=True) creator = models.ForeignKey('UserInfo', null=True, blank=True) create_time = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = "資產記錄表" def __str__(self): return '<{}> <{}> <{}>'.format(self.asset.idc.name, self.asset.cabinet_num, self.asset.cabinet_order) class ErrorLog(models.Model): ''' 錯誤日志記錄 ''' asset = models.ForeignKey('Asset', null=True, blank=True) title = models.CharField(max_length=64) content = models.TextField() create_time = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = "錯誤日志表" def __str__(self): return self.title
