CMDB
Posted 柳姑娘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CMDB相关的知识,希望对你有一定的参考价值。
资产采集的实现方案
1. agent模式
每一台服务器放一份agent程序,subprocess执行采集命令,requests提交数据
优点:简单,采集速度快
应用场景:机器多,性能要求降低
2. ssh模式
在服务器和API之间放置一台中控机 用ssh远程连接服务器 ,执行命令,获取结果,并发送给API
应用场景:机器少,性能要求高
优点:无agent 速度慢 ssh方式
例如:fabric ansible 封装了paramiko模块 批量执行命令
3. salt模式
saltstack(python写的)
在服务器和API之间放置一台中控机,中控机和服务器上分别安装saltstack,中控机上的salt执行命令获取资产信息
master
salve/minion
应用场景:已经用了saltstack 机器多 比ssh速度快
原理:
1 SaltStack 采用`C/S`模式,server端就是salt的master,client端就是minion,minion与master之间通过`ZeroMQ`消息队列通信。 2 3 minion上线后先与master端联系,把自己的`pub key`发过去,这时master端通过`salt-key -L`命令就会看到minion的key,接受该minion-key后,也就是master与minion已经互信。 4 5 master可以发送任何指令让minion执行了,salt有很多可执行模块,比如说cmd模块,在安装minion的时候已经自带了,它们通常位于你的python库中,`locate salt | grep /usr/`可以看到salt自带的所有东西。 6 7 这些模块是python写成的文件,里面会有好多函数,如cmd.run,当我们执行`salt \'*\' cmd.run \'uptime\'`的时候,master下发任务匹配到的minion上去,minion执行模块函数,并返回结果。 8 9 master监听4505和4506端口,4505对应的是ZMQ的PUB system,用来发送消息,4506对应的是REP system是来接受消息的。 10 具体步骤如下 11 12 ``` 13 1、Salt stack的Master与Minion之间通过ZeroMq进行消息传递,使用了ZeroMq的发布-订阅模式,连接方式包括tcp,ipc 14 2、salt命令,将cmd.run ls命令从salt.client.LocalClient.cmd_cli发布到master,获取一个Jodid,根据jobid获取命令执行结果。 15 3、master接收到命令后,将要执行的命令发送给客户端minion。 16 4、minion从消息总线上接收到要处理的命令,交给minion._handle_aes处理 17 5、minion._handle_aes发起一个本地线程调用cmdmod执行ls命令。线程执行完ls后,调用minion._return_pub方法,将执行结果通过消息总线返回给master 18 6、master接收到客户端返回的结果,调用master._handle_aes方法,将结果写的文件中 19 7、salt.client.LocalClient.cmd_cli通过轮询获取Job执行结果,将结果输出到终端。 20 ``` 21 22 #### saltstack 安装 23 24 [saltstack install](http://repo.saltstack.com/#rhel) 25 26 #### 修改minion配置文件 27 ``` 28 [root@linux-node2 ~]# vim /etc/salt/minion 29 master: 192.168.56.11 30 [root@linux-node2 ~]# vim /etc/salt/minion 31 master: 192.168.56.11 32 [root@linux-node1 pki]# pwd 33 /etc/salt/pki 34 [root@linux-node1 pki]# tree 35 . 36 ├── master 37 │ ├── master.pem 38 │ ├── master.pub 39 │ ├── minions 40 │ ├── minions_autosign 41 │ ├── minions_denied 42 │ ├── minions_pre 43 │ │ ├── linux-node1.example.com 44 │ │ └── linux-node2.example.com 45 │ └── minions_rejected 46 └── minion 47 ├── minion_master.pub 48 ├── minion.pem 49 └── minion.pub 50 [root@linux-node1 pki]# salt-key -A 51 [root@linux-node1 pki]# tree 52 . 53 ├── master 54 │ ├── master.pem 55 │ ├── master.pub 56 │ ├── minions 57 │ │ ├── linux-node1.example.com 58 │ │ └── linux-node2.example.com 59 │ ├── minions_autosign 60 │ ├── minions_denied 61 │ ├── minions_pre 62 │ └── minions_rejected 63 └── minion 64 ├── minion_master.pub 65 ├── minion.pem 66 └── minion.pub 67 ``` 68 69 #### 远程执行 70 ``` 71 [root@linux-node1 pki]# salt "*" test.ping 72 linux-node2.example.com: 73 True 74 linux-node1.example.com: 75 True 76 [root@linux-node1 pki]# salt "*" cmd.run \'w\' 77 linux-node1.example.com: 78 07:20:24 up 17:10, 1 user, load average: 0.00, 0.01, 0.05 79 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT 80 root pts/0 192.168.56.1 07:04 0.00s 0.30s 0.26s /usr/bin/python /usr/bin/salt * cmd.run w 81 linux-node2.example.com: 82 08:26:25 up 22:40, 2 users, load average: 0.15, 0.05, 0.06 83 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT 84 root tty1 Sat09 13:12m 0.02s 0.02s -bash 85 root pts/0 192.168.56.1 08:09 13:53 0.04s 0.04s -bash 86 ``` 87 88 #### 配置管理 89 ##### YAML 90 91 - 缩进: 92 - 两个空格 93 - 不能使用tab键 94 - 缩进代表层级关系 95 96 - 冒号: 97 - key: value 98 99 - 短横线代表list 100 101 #### satate模块 102 ``` 103 # vim /etc/salt/master 104 file_roots: 105 base: 106 - /srv/salt 107 # mkdir /srv/salt 108 # mkdir /srv/salt 109 # cd /srv/salt 110 # mkdir web 111 # cd web 112 # pwd 113 /srv/salt/web 114 # vim apache.sls 115 apache-install: 116 pkg.installed: 117 - names: 118 - httpd 119 - httpd-devel 120 121 apache-service: 122 service.running: 123 - name: httpd 124 - enable: True 125 126 # salt \'*\' state.sls web.apache 127 [root@linux-node2 salt]# cd /var/cache/salt/ 128 [root@linux-node2 salt]# tree 129 . 130 `-- minion 131 |-- extmods 132 |-- files 133 | `-- base 134 | `-- web 135 | `-- apache.sls 136 |-- pkg_refresh 137 `-- proc 138 `-- 20160605081351939477 139 # cat /var/cache/salt/minion/files/base/web/apache.sls 140 apache-install: 141 pkg.installed: 142 - names: 143 - httpd 144 - httpd-devel 145 146 apache-service: 147 service.running: 148 - name: httpd 149 - enable: True 150 # ps -ef|grep yum 151 root 34129 34103 1 08:13 ? 00:00:00 /usr/bin/python /usr/bin/yum --quiet check-update 152 root 34204 34149 0 08:14 pts/1 00:00:00 grep --color=auto yum 153 154 # cd /srv/salt/ 155 # vim top.sls 156 base: 157 \'linux-node1.example.com\': 158 - web.apache 159 \'linux-node2.example.com\': 160 - web.apache 161 # salt \'*\' state.highstate test=True 162 # salt \'*\' state.highstate 163 164 # lsof -i:4505 -n 165 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME 166 salt-mast 24739 root 13u IPv4 4637762 0t0 TCP *:4505 (LISTEN) 167 salt-mast 24739 root 15u IPv4 4640421 0t0 TCP 192.168.56.11:4505->192.168.56.11:48344 (ESTABLISHED) 168 salt-mast 24739 root 16u IPv4 4640542 0t0 TCP 192.168.56.11:4505->192.168.56.12:53039 (ESTABLISHED) 169 salt-mini 25378 root 25u IPv4 4640888 0t0 TCP 192.168.56.11:48344->192.168.56.11:4505 (ESTABLISHED) 170 ``` 171 172 #### 数据系统 173 174 ##### Grains 175 静态数据 当minion启动时收集的minion本地相关信息
4. puppet(ruby)每30分钟连接一次master,执行一次ruby脚本
场景:公司现在在使用puppet
代码流程:
资产采集部分 采集资产subprocess, 兼容性(agent,ssh,salt), 正则或字符串方法(插件) 1 配置文件:默认配置和自定义配置 2 开发可插拔插件(每个公司采集的资产信息不同) 配置--路径--对应插件(中间件的设计模式) 插件-反射----init文件(从配置文件中获取插件信息)--pluginmanage (获取和执行插件) 给插件设置统一的方法process (返回对应信息) 3 解决兼容问题 方法一:设置基类(做扩展时麻烦) 方法二:给process传参 commond 在commod函数中先做判断 4 插件的构造方法执行之前自定制一些操作 @classmethod def initial(cls) ..... return cls() 错误堆栈信息:try except 测试模式:debug 5 向API发送数据 从API获取未采集资产
问题:
唯一标识:
周期:2-3个月,3个人 你负责做什么? 3处借鉴了Django源码的设计模式: 1 默认配置和自定义配置 2 中间件---插件做成可插拔的模式,增加采集资源的插件时,只要写一个类(命令+结果格式化) 在配置文件中写上路径,就可以采集资源的信息 用到了反射 遇到的难题:唯一标识 1 唯一标识 所有物理硬件上的标识不能作为唯一标识 主板SN号:虚拟机的SN号可能相同 IP地址会变 Mac地址不准确 标准化: --主机名不重复,作为唯一标识 --流程标准化 --资产录入,机房,机柜,机柜位置 --装机时,需要将服务信息录入CMDB --资产采集 最终流程:标准化:主机名不重复。流程标准化:装机同时,主机名在cmdb中设置 步骤: agent: a. 装系统,初始化软件cmdb,运行cmdb --通过命令获取主机名 --写入本地指定文件 b. 将资产信息发送到API c.获取资产信息 -本地文件主机名!= 命令获取的主机名(按照文件中的主机名) -本地文件住居明==命令获取的文件主机名 ssh/salt: 中控机:获取未采集主机名列表
线程池:
1 2 线程池 2 提高并发 3 python2: 进程池 4 python3:线程池 进程池 5 代码示例: 6 from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor 7 8 def task(i) 9 print(i) 10 11 p=ThreadPoolExecutor(10) 12 for row in range(100) 13 p.submit(task,row)
API验证:
为什么要做API验证?
数据传输过程中,保证数据不被篡改
如何设计?
--和Tornado中的加密Cookie类似
--客户端创建动态key md5(key+time)|time
--服务端 添加限制
-- 时间限制
-- 算法规则限制
-- 已访问记录 2s
ps :黑客窃取数据后,速度比正常汇报速度快,解决方法:数据加密 crypto模块 AES
1 #API验证 2 # 发令牌 静态, 隐患:易被他人截取 3 4 import requests 5 key=\'ncjfsvnjsflbvfjslgbvhglbhfbh\' 6 response=requests.get(\'http://127.0.0.1:8000/api/asset/\',headers={\'openkey\':key}) 7 print(response.text) 8 9 # 改良 动态令牌 隐患:易被他人截取 10 import time 11 import requests 12 import hashlib 13 # 14 ctime=time.time() 15 key=\'vmkdsf;nvfglnbglbngjflbn\' 16 new_key=\'%s|%s\'%(key,ctime) 17 18 m=hashlib.md5() 19 m.update(bytes(new_key,encoding=\'utf8\')) 20 md5_key=m.hexdigest() 21 22 md5_time_key=\'%s|%s\'%(md5_key,ctime) 23 response=requests.get(\'http://127.0.0.1:8000/api/asset/\',headers={\'openkey\':md5_time_key}) 24 print(response.text) 25 26 #解决方法 27 # ---记录已发送的md5_time_key 28 # ---时间限制:将10s以外的排除 29 # 将两个限制结合起来 30 31 #隐患:黑客网速快 32 # 不管:搭建内网 33 # 管:数据加密
最终代码
1 def post_asset(self,server_info): 2 #数据加密 3 server_info=json.dumps(server_info) 4 server_info=self.xxxxxx(server_info) 5 #API验证 6 ctime=time.time() 7 key=\'vmkdsf;nvfglnbglbngjflbn\' 8 new_key=\'%s|%s\'%(key,ctime) 9 10 m=hashlib.md5() 11 m.update(bytes(new_key,encoding=\'utf8\')) 12 md5_key=m.hexdigest() 13 14 md5_time_key=\'%s|%s\'%(md5_key,ctime) 15 16 response=requests.get( 17 url=settings.API, 18 headers={\'openkey\':md5_time_key,\'Content-Type\':\'application/json\'}, 19 data=server_info) 20 # response = requests.get(settings.API,headers={\'openkey\': md5_time_key,},json=server_info) 21 return response.text
1 def api_confirm(func): 2 def wrapper(request): 3 api_key_record = {} 4 client_md5_time_key = request.META.get(\'HTTP_OPENKEY\') 5 client_md5_key, client_time = client_md5_time_key.split(\'|\') 6 client_time = float(client_time) 7 server_time = time.time() 8 9 # 第一关 排除超过10秒的请求 10 if server_time - client_time > 10: 11 return HttpResponse(\'你网络太慢了吧,重新发\') 12 # 第二关:匹配MD5值 13 14 temp = "%s|%s" % (settings.AUTH_KEY, client_time,) 15 m = hashlib.md5() 16 m.update(bytes(temp, encoding=\'utf-8\')) 17 server_md5_key = m.hexdigest() 18 if server_md5_key != client_md5_key: 19 return HttpResponse(\'修改时间了吧,你还嫩点\') 20 21 # 将过期的MD5值记录删除 22 for k in list(api_key_record.keys()): 23 v = api_key_record[k] 24 if server_time > v: 25 del api_key_record[k] 26 27 # 第三关:检查此MD5值10秒之内是否访问过 28 if client_md5_time_key in api_key_record: 29 return HttpResponse(\'是你,是你,就是你,heck\') 30 else: 31 api_key_record[client_md5_time_key] = client_time + 10 32 return func(request) 33 return wrapper
数据库设计
1 from django.db import models 2 3 4 class UserProfile(models.Model): 5 """ 6 用户信息 7 """ 8 name = models.CharField(u\'姓名\', max_length=32) 9 email = models.EmailField(u\'邮箱\') 10 phone = models.CharField(u\'座机\', max_length=32) 11 mobile = models.CharField(u\'手机\', max_length=32) 12 13 class Meta: 14 verbose_name_plural = "用户表" 15 16 def __str__(self): 17 return self.name 18 19 20 class AdminInfo(models.Model): 21 """ 22 用户登陆相关信息 23 """ 24 user_info = models.OneToOneField("UserProfile") 25 username = models.CharField(u\'用户名\', max_length=64) 26 password = models.CharField(u\'密码\', max_length=64) 27 28 class Meta: 29 verbose_name_plural = "管理员表" 30 31 def __str__(self): 32 return self.user_info.name 33 34 35 class UserGroup(models.Model): 36 """ 37 用户组 38 """ 39 name = models.CharField(max_length=32, unique=True) 40 users = models.ManyToManyField(\'UserProfile\') 41 42 class Meta: 43 verbose_name_plural = "用户组表" 44 45 def __str__(self): 46 return self.name 47 48 49 class BusinessUnit(models.Model): 50 """ 51 业务线 52 """ 53 name = models.CharField(\'业务线\', max_length=64, unique=True) 54 contact = models.ForeignKey(\'UserGroup\', verbose_name=\'业务联系人\', related_name=\'c\') 55 manager = models.ForeignKey(\'UserGroup\', verbose_name=\'系统管理员\', related_name=\'m\') 56 57 class Meta: 58 verbose_name_plural = "业务线表" 简易的CMDB服务端