nagiosplugin: 如何根据值显示不同的fmt_metric?

0 投票
1 回答
733 浏览
提问于 2025-04-18 08:10

我正在写一个Nagios插件,这个插件使用来自sslyze的xml输出,来根据Qualys服务器评分指南计算SSL评分。

这是我的代码:

            if certificateMatchesServerHostname == 'True' and expire_in.days > 0 and validationResult == 'ok':
                ...
                final_score = protocol_score * 0.3 + key_score * 0.3 + cipher_score * 0.4
                return [nap.Metric('sslscore', final_score, min=0, max=100)]
            elif certificateMatchesServerHostname != 'True':
                return [nap.Metric('serverHostname', hostnameValidation[0].attrib['serverHostname'])]
            elif expire_in.days <= 0:
                return [nap.Metric('expireInDays', expire_in.days)]
            elif validationResult != 'ok':
                return [nap.Metric('validationResult', validationResult)]


@nap.guarded
def main():
    check = nap.Check(
        SslConfiguration(),
        nap.ScalarContext('sslscore', nap.Range('@65:80'), nap.Range('@0:65')),
        nap.ScalarContext('serverHostname', fmt_metric='The certificate does not match the host name {value}'),
        nap.ScalarContext('expireInDays', nap.Range('@:0'), fmt_metric='The certificate expired {value} days ago'),
        nap.ScalarContext('validationResult', fmt_metric='This server\'s certificate is not trusted: {value}'))
    check.main(timeout=60)

我之所以需要使用多个ScalarContext,是因为我想在SSL证书出现问题时显示不同的fmt_metric,比如证书不匹配、过期、不被信任等等。

根据上面的代码,输出看起来像这样:

SSLCONFIGURATION CRITICAL - The certificate does not match the host name a.b.c.d (outside range 0:)
critical: The certificate does not match the host name a.b.c.d (outside range 0:)
| serverHostname=a.b.c.d

我真正想显示的是:

SSLCONFIGURATION CRITICAL - final_score is 0 (The certificate does not match the host name a.b.c.d) | sslscore=0;@65:80;@65;0;100

所以,我有一些问题:

  1. 我该如何在只有一个上下文sslscore中,根据sslscore的值显示不同的fmt_metric

  2. 如何去掉多余的那一行(第二行)?

    critical: The certificate does not match the host name a.b.c.d (outside range 0:)
    
  3. 如何把指标(第三行)移动到第一行的末尾?

1 个回答

0

在朋友的帮助下,我终于解决了这个问题。

关于第一个问题,我们可以使用 nagiosplugin.summary 这个模块来修改状态行,像这样:

class SslConfiguration(nap.Resource):
    def __init__(self, host, port):
        self.host = host
        self.port = port

    def check(self):
            ...
        if hostname_validation.startswith('OK') and expire_in.days > 0 and is_trusted == 'OK':
            final_score = protocol_score * 0.3 + key_score * 0.3 + cipher_score * 0.4
        else:
            final_score = 0
        return (hostname_validation, is_trusted, expire_in.days, final_score)

    def probe(self):
        if self.check()[3] > 0:
            return [nap.Metric('sslscore', self.check()[3])]
        elif not self.check()[0].startswith('OK'):
            return [nap.Metric('sslscore', 0, context='serverHostname')]
        elif self.check()[1] != 'OK':
            return [nap.Metric('sslscore', 0, context='validationResult')]
        elif self.check()[2] <= 0:
            return [nap.Metric('sslscore', 0, context='expireInDays')]


class SslSummary(nap.Summary):
    def __init__(self, host, port):
        self.host = host
        self.port = port

    def status_line(self, results):
        ssl_configuration = SslConfiguration(self.host, self.port)
        if results['sslscore'].context.name == 'serverHostname':
            return "sslscore is 0 ({0})".format(ssl_configuration.check()[0])
        elif results['sslscore'].context.name == 'validationResult':
            return "sslscore is 0 ({0})".format(ssl_configuration.check()[1])
        elif results['sslscore'].context.name == 'expireInDays':
            return "sslscore is 0 (The certificate expired {0} days ago)".format(ssl_configuration.check()[2])

    def problem(self, results):
        return self.status_line(results)

第二个和第三个问题可以通过把 main()verbose 参数设置为零来解决:

@nap.guarded
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-H', '--host', type=str, required=True)
    parser.add_argument('-p', '--port', type=int, default=443)
    parser.add_argument('-v', '--verbose', action='count', default=0, help="increase output verbosity (use up to 3 times)")
    parser.add_argument('-t', '--timeout', type=int, default=60)
    args = parser.parse_args()

    check = nap.Check(
        SslConfiguration(args.host, args.port),
        nap.ScalarContext('sslscore', nap.Range('@65:80'), nap.Range('@0:65')),
        nap.ScalarContext('serverHostname', nap.Range('@65:80'), nap.Range('@0:65')),
        nap.ScalarContext('validationResult', nap.Range('@65:80'), nap.Range('@0:65')),
        nap.ScalarContext('expireInDays', nap.Range('@65:80'), nap.Range('@0:65')),
        SslSummary(args.host, args.port))
    check.main(args.verbose, args.timeout)

现在输出的信息可以帮助系统管理员了解发生了什么:

check_ssl_configuration.py -H google.com
SSLCONFIGURATION OK - sslscore is 87 | sslscore=87.0;@65:80;@65

check_ssl_configuration.py -H 173.194.127.169
SSLCONFIGURATION CRITICAL - sslscore is 0 (FAILED - Certificate does NOT match 173.194.127.169) | sslscore=0;@65:80;@65

撰写回答