Source code for libnrdpd.nrdp

# Copyright 2020 Hoplite Industries, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Funcitons for submitting results to the NRDP endpiont."""

import json
import logging
import urllib.error
import urllib.request
import urllib.parse

# Local imports
from . import config
from . import error
from . import task as tasklib

logging.getLogger(__name__).addHandler(logging.NullHandler())


[docs]def submit(cfg: config.Config, task: tasklib.Task, send_host: bool = False): """Submit a completed task to nagios via nrdp. This will submit the request to all servers in the servers config. Parameters: cfg (libnrdpd.config.Config): libnrdpd Config object task (:class:`libnrdpd.task.Task`): Completed task that needs to be sent to the central nagios server. send_host: If ``True`` send a host check result as well. Raises: :class:`libnrdpd.error.NotComplete`: Raised when an uncompleted task is passed in. """ log = logging.getLogger("%s.Nrdp.submit" % __name__) if task.expired: # Manufacture fake CRITICAL submission results code = error.Status.CRITICAL message = "TIMEOUT: Plugin timed out after %0.2f seconds" % ( task.elapsed ) else: if task.stderr: # This must be first in order to accommodate for the # possibility that we can't fork a sub process. Being first # allows us to bypass a bunch of other assumptions. # If we get output on stderr this is a failure of the # API contract. Report it as an error. code = error.Status.CRITICAL message = "Check failed with stderr output:\n%s" % (task.stderr) elif task.status is None: raise error.NotComplete( error.Err.INCOMPLETE, "%s.Nrdp.submit called with an uncompleted task [check:%s]" % (__name__, task.check.name), ) elif task.status < 0: # A signal killed the process code = error.Status.CRITICAL message = "Check died with signal %d" % abs(code) else: # Normal processing try: code = error.Status(task.status) message = task.stdout except ValueError: code = error.Status.CRITICAL message = "Check exited with unknown code: %d" % (task.status) check_results = { "checkresults": [ { "checkresult": {"type": "service"}, "hostname": cfg.host, "servicename": task.check.name, "state": code.value, "output": message, }, ] } if send_host: check_results["checkresults"].append( { "checkresult": {"type": "host"}, "hostname": cfg.host, "state": "0", "output": "Host alive", } ) payload = { "cmd": "submitcheck", "token": cfg.token, "json": json.dumps(check_results), } data = urllib.parse.urlencode(payload).encode("utf-8") for url in cfg.servers: try: req = urllib.request.urlopen( url, timeout=60, data=data, cafile=cfg.cacert ) httpstatus = req.getcode() if httpstatus != 200: log.error( "Submission to %s failed http status: %d", url, httpstatus, ) except urllib.error.URLError as err: log.error("Submission to %s failed: %s", url, err) continue