对应SQL型数据库,对于存放的数据,我们必须设置相应的键,并且按照键来填写每一行的数据信息。在面对一些格式不确定的信息时,使用SQL型数据库就较为困难。
MongoDB 是一个基于分布式文件存储的数据库。它将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
例如,当我们存储不同网络设备重要信息时,可以按照如下组织的结构进行存储,并且每一个设备的格式可以不同:
如果后续有其他信息,也方便添加和修改。
MongoDB的优势:
使用Docker安装:https://hub.docker.com/_/mongo
从docker拉取镜像:
docker pull mango
创建容器:
docker run --name some-mongo(容器名称) -d(后台运行) mongo:tag(mongoDB版本,没有tag表示latest)
进入容器数据库:
docker exec -it some-mongo mongo
创建数据库:
use admin(默认管理员数据库)
创建属于自己的系统管理员:
db.createUser({user:"admin",pwd:"Cisc0123",roles:["root"]})
使用管理员对admin数据库进行认证:
db.auth('admin','Cisc0123')
查看数据库:
show dbs
创建自定义数据库,和管理员:
use dev_info
db.createUser({user:'dev_admin',pwd:"Cisc0123",roles:[{role:"dbOwner",db:"dev_info"}]})
db.auth('dev_admin','Cisc0123')
创建集合并插入文档数据:
db.device.insert({dev_vendor:'Cisco'})
创建了一个device的集合,并插入的文档数据。
查看数据库中集合和集合中文档信息:
show tables
db.device.find()
在文档内容较多的时候,如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
db.device.find().pretty()
如果文档中含有数字信息,可以使用条件操作符对其进行过滤查看。MongoDB中条件操作符有:
(>) 大于 - $gt
(<) 小于 - $lt
(>=) 大于等于 - $gte
(<= ) 小于等于 - $lte
查找device集合中,设备数量大于10的文档:
db.device.insert({dev_vendor:'Cisco',number:20})
db.device.insert({dev_vendor:'Huawei',number:5})
db.device.find({number : {$gt : 10}})
类似于SQL语句:
Select * from device where number > 10;
更新数据:
db.device.update({dev_vendor : "Cisco" },{$set:{dev_vendor : "Huawei" }},{multi:true})
以上语句只会修改第一条发现的文档,如果你要修改多条相同的文档,则需要设置 multi 参数为 true。
删除文档:
db.device.remove({dev_vendor : "Huawei" })
默认会匹配多条记录信息,如果想输出第一条找到的记录:
db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)
删除集合device中的所有文档信息:
db.device.remove({})
删除集合:
db.device.drop()
删除数据库:
db.dropDatabase()
进入数据库后使用如上命令删除数据库。
实验目的:
将获取的SNMP信息根据自己组织的数据格式写入MongoDB中:
实验环境:
CSR1000v,IP地址为192.168.0.166。
实验步骤:
1.获取SNMP返回信息并处理:
snmpv2_get.py代码:
from pysnmp.hlapi import *
from pysnmp.entity.rfc3413.oneliner import cmdgen
# SNMP GET方法代码:
def snmpv2_get(ip, community, oid, port=161):
# varBinds是列表,列表中的每个元素的类型是ObjectType(该类型的对象表示MIB variable)
error_indication, error_status, error_index, var_binds = next(
getCmd(SnmpEngine(),
CommunityData(community),
UdpTransportTarget((ip, port)),
ContextData(),
ObjectType(ObjectIdentity(oid)))
)
# 错误处理
if error_indication:
print(error_indication)
elif error_index:
print('%s at %s' % (
error_status,
error_index and var_binds[int(error_index) - 1][0] or '?'
)
)
# 如果返回结果又多行,需要拼接后返回
result = ""
for varBind in var_binds:
# 返回结果
result = result + varBind.prettyPrint()
# 返回的为一个元组,OID与字符串结果
# print(result)
return result.split("=")[0].strip(), result.split("=")[1].strip()
# 当多个叶节点的时候(例如接口信息),使用GETNEXT,返回多个信息
def snmpv2_getnext(ip, community, oid, port=161):
cmd_gen = cmdgen.CommandGenerator()
error_indication, error_status, error_index, var_bind_table = cmd_gen.nextCmd(
cmdgen.CommunityData(community), # 设置community
cmdgen.UdpTransportTarget((ip, port)), # 设置IP地址和端口号
oid, # 设置OID
)
# 错误处理
if error_indication:
print(error_indication)
elif error_status:
print(error_status)
result = []
# varBindTable是个list,元素的个数可能有好多个。它的元素也是list,这个list里的元素是ObjectType,个数只有1个。
for var_bind_table_row in var_bind_table:
for item in var_bind_table_row:
result.append((item.prettyPrint().split("=")[0].strip(), item.prettyPrint().split("=")[1].strip()))
return result
2.调用获取SNMP信息函数,将返回的SNMP信息按照自己组织的格式写入mongoDB中:
write_dev_info_to_db.py
from snmpv2_func import snmpv2_get, snmpv2_getnext
from pymongo import *
from pprint import pprint
import datetime
import time
# 将信息写入mongoDB的函数
def write_info_to_db(dict_info):
# 设置Mongodb的参数,dev_admin处为管理员账号,Cisc0123为密码,192.168.0.166位存放数据库的位置,27017为默认port,device_info为数据库名字
client = MongoClient('mongodb://dev_admin:[email protected]:27017/device_info')
db = client['device_info']
# 插入文档信息
db.dev_info.insert_one(dict_info)
print('*'*50+'写入信息:'+'*'*50)
for obj in db.dev_info.find():
pprint(obj, indent=4)
if __name__ == '__main__':
print("收集路由器数据中,按ctrl+c退出")
try:
while True:
# 获取接口名称信息
if_name_raw = snmpv2_getnext("192.168.0.66", "tcpipro", "1.3.6.1.2.1.2.2.1.2", port=161)
if_name_list = [i[1] for i in if_name_raw]
# 获取接口速率信息
if_speed_raw = snmpv2_getnext("192.168.0.66", "tcpipro", "1.3.6.1.2.1.2.2.1.5", port=161)
if_speed_list = [i[1] for i in if_speed_raw]
# 获取接口入字节数
if_in_raw = snmpv2_getnext("192.168.0.66", "tcpipro", "1.3.6.1.2.1.2.2.1.10", port=161)
if_in_list = [i[1] for i in if_in_raw]
# 获取接口出字节数
if_out_raw = snmpv2_getnext("192.168.0.66", "tcpipro", "1.3.6.1.2.1.2.2.1.16", port=161)
if_out_list = [i[1] for i in if_out_raw]
# 5秒内CPU利用率
cpu_usage = snmpv2_get("192.168.0.66", "tcpipro", "1.3.6.1.4.1.9.9.109.1.1.1.1.3.7", port=161)
# 内存使用
mem_usage = snmpv2_get("192.168.0.66", "tcpipro", "1.3.6.1.4.1.9.9.109.1.1.1.1.12.7", port=161)
# 内存空闲
mem_free = snmpv2_get("192.168.0.66", "tcpipro", "1.3.6.1.4.1.9.9.109.1.1.1.1.13.7", port=161)
# 记录时间
record_time = datetime.datetime.now()
# 将其他参数写入一个字典
other_info_dict = {'cpu_usage:': cpu_usage[1], 'mem_usage': mem_usage[1], 'mem_free': mem_free[1],
'record_time': record_time, 'ip': '192.168.0.66'}
# 组织写入的文档数据格式
final_list = []
for name, speed, in_bytes, out_bytes in zip(if_name_list, if_speed_list, if_in_list, if_out_list):
final_list.append({'name': name, 'speed': speed, 'in_bytes': in_bytes, 'out_bytes': out_bytes})
# pprint(final_list, indent=4)
final_dict = {"int_info": final_list, 'other_info': other_info_dict}
write_info_to_db(final_dict)
time.sleep(10)
except KeyboardInterrupt: # 捕获Ctrl+C,打印信息并退出
print("Crtl+C Pressed. Shutting down.")
3.测试结果:
参考资料:
https://www.runoob.com/mongodb/mongodb-tutorial.html
https://www.bilibili.com/video/BV1Kt411c7tH?p=2