使用Python在MongoDB中查询变量键的数据显示结果

2 投票
1 回答
1191 浏览
提问于 2025-04-18 04:06

我现在在做一个使用SaltStack的项目,里面用到了MongoDB来存储结果,我想查询这些结果以便做报告。不过,返回的数据写入数据库的方式看起来是这样的:

db.hostname21.find({"20140421035007474763" : {$exists : 1}}, {_id: 0}).pretty()

{
     "fun" : "state.sls",
     "20140421035007474763" : {
            "file_|-Get-Logins-Stats_|-/scripts/server_logins_stats_|-managed" : {
                    "comment" : "File /scripts/server_logins_stats is in the correct state",
                    "__run_num__" : 2,
                    "changes" : {

                    },
                    "name" : "/scripts/server_logins_stats",
                    "result" : true
            },
            "service_|-Logger_|-rsyslog_|-running" : {
                    "comment" : "Service rsyslog is already enabled, and is in the desired state",
                    "__run_num__" : 1,
                    "changes" : {

                    },
                    "name" : "rsyslog",
                    "result" : true
            },
            "cmd_|-Run_Script_|-/scripts/server_logins_stats_|-run" : {
                    "comment" : "Command \"/scripts/server_logins_stats\" run",
                    "__run_num__" : 4,
                    "changes" : {
                            "pid" : 20899,
                            "retcode" : 0,
                            "stderr" : "",
                            "stdout" : "0"
                    },
                    "name" : "/scripts/server_logins_stats",
                    "result" : true
            },
            "cron_|-Schedule_Run_|-/scripts/server_logins_stats_|-present" : {
                    "comment" : "Cron /scripts/server_logins_stats already present",
                    "__run_num__" : 3,
                    "changes" : {

                    },
                    "name" : "/scripts/server_logins_stats",
                    "result" : true
            },
            "pkg_|-nc_|-nc_|-installed" : {
                    "comment" : "Package nc is already installed",
                    "__run_num__" : 0,
                    "changes" : {

                    },
                    "name" : "nc",
                    "result" : true
            }
    }
}

从这里可以看到,数据的键(也就是标识符)总是在变化,而不是有一个固定的键来标识每个脚本。不过,我发现失败的记录格式比较一致,只是没有任何键来表明这是一个失败的记录,只有一串字符串数组:

       "20140421041507478163" : [
            "Pillar failed to render with the following messages:",
            "Specified SLS 'globals' in environment 'Production' is not available on the salt master"
       ],
       "fun" : "state.sls"

所以我最终想做的是能够针对每个失败的记录进行报告,识别出作业、主机和失败的性质,以及一段时间内成功和失败的总数。如果你注意到,每个主机(也叫从机)都有自己的数据集合。因此,我写了一个Python脚本,可以遍历这些集合,以确定作业是否在该主机上实际执行过:

import datetime
import pymongo


#hosts = ["mongoDBStaging", "mongoDBUAT"]
hosts = ["mongodbuat"]

for host in hosts:
    conn = pymongo.Connection(host)
    mdb = conn['salt']
    collections = set(mdb.collection_names())


    hosts = []
    jids = []

    # for every collection, identify whether it is a host or a job
    for c in collections:   
        # if the collection is a host add it to the host array
        if not (len(c) == 20 and int(c)):
            #print "{0} is a host".format(c)
            hosts.append(c)
        # other  wise add it to the job array
        else:
            #print "{0} is a jid".format(c)
            jids.append(c)


    for h in hosts:
        # for every job in a host connect to that collection 
        # and search for the job id to see if it exists 
        # and what its return was so we can report on that info
        for j in jids:
            coll = conn['salt'][h]
            #print "%s collection, %s jid" % (coll, j)
            for doc in coll.find({j: {'$exists': True}, "fun": "state.sls"}, {"_id": 0}):
                print "{0}".format(coll)
                print "{0} is a doc".format(doc)

但我在查询结果时遇到困难,无法确定作业是否成功。我想从返回的文档中提取元素,以便查看每个文档的结果。

如果有人有建议,能让我在键不断变化的情况下,稳定地查询到结果,那将非常有帮助。

1 个回答

1

如果有人在想这个问题,我自己解决了。使用了下面的Python代码。虽然这不是性能最好的方法,也没有充分利用MongoDB,但确实能工作。我可能会建议更新盐返回器,让它更好地使用MongoDB,因为在命令行中查询的功能比较有限。

import datetime
import pymongo
import json
import re

hosts = ["mongodbuat"]

# initialize failures and successes
failures = 0
successes = 0

for host in hosts:
    conn = pymongo.Connection(host)
    mdb = conn['salt']
    collections = set(mdb.collection_names())

    hosts = []
    jids = []

    # for every collection, identify whether it is a host or a job
    for c in collections:   
        # if the collection is a host add it to the host array
        if not (len(c) == 20 and int(c)):
            hosts.append(c)
        # otherwise add it to the job array
        else:
            jids.append(c)


    for h in hosts:
        # for every job in a host connect to that collection 
        # and search for the job id to see if it exists 
        # and what its return was so we can report on that info
        for j in jids:
            coll = conn['salt'][h]

            # search for the json documents returned from mongodb
            # if the jobid exists in that host
            for doc in coll.find({j: {'$exists': True}, "fun": "state.sls"}, {"_id": 0}):

                # if the jobid exists find the host name in a readable format
                c = str(coll)
                thishost = ''
                match = re.search('(\w+)\.spottrading\.com',c)
                if match:
                    thishost = match.group(1)

                # search the document returned in the form of a dictionary for
                # the states you want to report on
                for jobid, states in doc.iteritems():
                    if re.search('\d+', jobid):
                        print '\njob id =', jobid
                        if isinstance(states, list):
                            print states
                            failures += 1
                        elif isinstance(states, dict):
                            for job, data in states.iteritems():
                                print '\tjob: {0}, result: {1}'.format(job, data[u'result'])
                            successes += 1

print "{0} successes, {1} failures".format(successes, failures)                         

撰写回答