CMDB开发
一:CMDB简介
CMDB --Configuration Management Database 配置管理数据库, CMDB存储与管理企业IT架构中设备的各种配置信息,它与所有服务支持和服务交付流程都紧密相联,支持这些流程的运转、发挥配置信息的价值,同时依赖于相关流程保证数据的准确性。
CMDB相关功能:
- 用户管理,记录测试,开发,运维人员的用户表
 - 业务线管理,需要记录业务的详情
 - 项目管理,指定此项目用属于哪条业务线,以及项目详情
 - 应用管理,指定此应用的开发人员,属于哪个项目,和代码地址,部署目录,部署集群,依赖的应用,软件等信息
 - 主机管理,包括云主机,物理机,主机属于哪个集群,运行着哪些软件,主机管理员,连接哪些网络设备,云主机的资源池,存储等相关信息
 - 主机变更管理,主机的一些信息变更,例如管理员,所属集群等信息更改,连接的网络变更等
 - 网络设备管理,主要记录网络设备的详细信息,及网络设备连接的上级设备
 - IP管理,IP属于哪个主机,哪个网段, 是否被占用等
 
二:CMDB实现的四种方式
一:Agent方式
Agent方式,可以将服务器上面的Agent程序作定时任务,定时将资产信息提交到指定API录入数据库。本质就是每个服务器在本地执行subprocess.getoutput(cmd)命令,获取结果并处理,调用API接口将数据录入数据库,最后通过web页面将结果展示给CMDB管理员
优点:速度快
缺点:每台服务器都要部署agent脚本
适用场景:服务器较多

二:ssh方式(paramiko模块)
中控机通过paramiko(python模块)登录到各个服务器上,然后执行命令去获取各个服务器上的信息,然后调用API接口将数据存储到数据库中。
优点:不用部署agent
缺点:速度慢
适用场景:服务器数量不多
代码实现:
import paramiko # 创建SSH对象 ssh = paramiko.SSHClient() # 允许连接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接服务器 ssh.connect(hostname='10.0.0.12', port=22, username='root', password='123456') # 执行命令 stdin, stdout, stderr = ssh.exec_command('ip a') # 获取命令结果 result = stdout.read() # 关闭连接 ssh.close()

三:saltstack方式
这个方案本质上和第二种方案大致是差不多的流程,中控机发送命令给服务器执行。服务器将结果放入另一个队列中,中控机获取将服务信息发送到API进而录入数据库。
优点:速度快,开发成本低
缺点:依赖第三方工具,每台服务器都要部署salt-minion
适用场景:公司之前一直使用此方式

saltstack的部署:
一:安装和配置 master端: """ 1. 安装salt-master yum install salt-master 2. 修改配置文件:/etc/salt/master interface: 10.0.0.11 # 表示Master的IP 3. 启动 service salt-master start """ slave端: """ 1. 安装salt-minion yum install salt-minion 2. 修改配置文件 /etc/salt/minion master: 10.0.0.11 # master的地址 或 master: - 10.0.0.11 - 10.0.0.12 random_master: True id: c2.salt.com # 客户端在salt-master中显示的唯一ID 3. 启动 service salt-minion start """ 二:授权 """ 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 """ 三:执行 在master服务器上对salve进行远程操作 salt 'c2.salt.com' cmd.run 'ifconfig' salt '*' cmd.run 'ifconfig' 基于api的方式: import salt.client local = salt.client.LocalClient() result = local.cmd('c2.salt.com', 'cmd.run', ['ifconfig'])
四:Puppet方式(了解)
基于Puppet的factor和report功能实现
puppet中默认自带了5个report,放置在【/usr/lib/ruby/site_ruby/1.8/puppet/reports/】路径下。如果需要执行某个report,那么就在puppet的master的配置文件中做如下配置: ######################## on master ################### /etc/puppet/puppet.conf [main] reports = store #默认 #report = true #默认 #pluginsync = true #默认 ####################### on client ##################### /etc/puppet/puppet.conf [main] #report = true #默认 [agent] runinterval = 10 server = master.puppet.com certname = c1.puppet.com 如上述设置之后,每次执行client和master同步,就会在master服务器的 【/var/lib/puppet/reports】路径下创建一个文件,主动执行:puppet agent --test
在 /etc/puppet/modules 目录下创建如下文件结构: modules └── cmdb ├── lib │ └── puppet │ └── reports │ └── cmdb.rb └── manifests └── init.pp ################ cmdb.rb ################ # cmdb.rb require 'puppet' require 'fileutils' require 'puppet/util' SEPARATOR = [Regexp.escape(File::SEPARATOR.to_s), Regexp.escape(File::ALT_SEPARATOR.to_s)].join Puppet::Reports.register_report(:cmdb) do desc "Store server info These files collect quickly -- one every half hour -- so it is a good idea to perform some maintenance on them if you use this report (it's the only default report)." def process certname = self.name now = Time.now.gmtime File.open("/tmp/cmdb.json",'a') do |f| f.write(certname) f.write(' | ') f.write(now) f.write("\r\n") end end end ################ 配置 ################ /etc/puppet/puppet.conf [main] reports = cmdb #report = true #默认 #pluginsync = true #默认
$LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__)) require "rubygems" require 'pp' require 'json' require 'utils' def dmi_get_ram(cmd) ram_slot = [] key_map = { 'Size' => 'capacity', 'Serial Number' => 'sn', 'Type' => 'model', 'Manufacturer' => 'manufactory', 'Locator' => 'slot', } output = Utils.facter_exec(cmd) devices = output.split('Memory Device') devices.each do |d| next if d.strip.empty? segment = {} d.strip.split("\n\t").each do |line| key, value = line.strip.split(":") if key_map.has_key?(key.strip) if key.strip == 'Size' segment[key_map['Size']] = value.chomp("MB").strip.to_i / 1024.0 # unit GB else segment[key_map[key.strip]] = value ? value.strip : '' end end end ram_slot.push(segment) unless segment.empty? end return ram_slot end Facter.add("ram") do confine :kernel => "Linux" setcode do ram_slot = [] cmd = "dmidecode -q -t 17 2>/dev/null" ram_slot = dmi_get_ram(cmd) JSON.dump(ram_slot) end end Facter.add("ram") do confine :kernel => 'windows' setcode do ram_slot = [] if Facter.value(:manufacturer) =~ /.*HP.*/i cli = 'C:\cmdb_report\dmidecode.exe' cmd = "#{cli} -q -t 17" ram_slot = dmi_get_ram(cmd) if File.exist?(cli) else require 'facter/util/wmi' Facter::Util::WMI.execquery("select * from Win32_PhysicalMemory").each do | item | if item.DeviceLocator slot = item.DeviceLocator.strip else slot = '' end if item.PartNumber model = item.PartNumber.strip else model = '' end if item.SerialNumber sn = item.SerialNumber.strip else sn = '' end if item.Manufacturer manufactory = item.Manufacturer.strip else manufactory = '' end ram_slot.push({ 'capacity' => item.Capacity.to_i / (1024**3), # unit GB 'slot' => slot, 'model' => model, 'sn' => sn, 'manufactory' => manufactory, }) end end JSON.dump(ram_slot) end end
                    
                
                
            
        
浙公网安备 33010602011771号