Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1 @@
from . import nsca_check, nsca_server

View file

@ -0,0 +1,112 @@
# (Copyright) 2015 ABF OSIELL <http://osiell.com>
# (Copyright) 2018 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging
from odoo import _, api, fields, models
from odoo.tools.safe_eval import safe_eval
_logger = logging.getLogger(__name__)
class NscaCheck(models.Model):
_name = "nsca.check"
_description = "NSCA Check"
_inherits = {"ir.cron": "cron_id"}
cron_id = fields.Many2one(
"ir.cron", string="Cron", required=True, ondelete="cascade", readonly=True
)
server_id = fields.Many2one("nsca.server", string="Server", required=True)
service = fields.Char(required=True)
nsca_model = fields.Char("NSCA Model")
nsca_function = fields.Char("Method")
nsca_args = fields.Char("Arguments")
allow_void_result = fields.Boolean(
"Allow void result",
default=False,
help="By default, a CRITICAL message is sent if the method does not "
"return.\nIf checked, no message will be sent in such a case.",
)
@api.model
def default_get(self, fields_list):
"""Set some default values on the fly, without overriding fields (which
has the side effect to re-create the fields on the current model).
"""
res = super(NscaCheck, self).default_get(fields_list)
res["name"] = "TEMP" # Required on 'ir.cron', replaced later
res["interval_number"] = 10
res["interval_type"] = "minutes"
return res
def _force_values(self):
"""Force some values:
- Compute the name of the NSCA check to be readable
among the others 'ir.cron' records.
"""
model = self.env["ir.model"].search([("model", "=", self._name)])
for check in self:
vals = {
"name": "{} - {}".format(_("NSCA Check"), check.service),
"model_id": model.id,
"state": "code",
"code": "model._cron_check(%s,)" % check.id,
"doall": False,
"numbercall": -1,
}
res = super(NscaCheck, check).write(vals)
return res
@api.model
def create(self, vals):
if not vals.get("model_id", False):
vals["model_id"] = (
self.env["ir.model"].search([("model", "=", self._name)]).id
)
if not vals.get("state", False):
vals["state"] = "code"
check = super(NscaCheck, self).create(vals)
check._force_values()
return check
def write(self, vals):
res = super(NscaCheck, self).write(vals)
if "service" in vals:
self._force_values()
return res
@api.model
def _cron_check(self, check_id):
self.env["nsca.server"]._check_send_nsca_command()
check = self.browse(check_id)
rc, message, performance = 3, "Unknown", {}
try:
NscaModel = self.env[check.nsca_model]
results = {"model": NscaModel}
safe_eval(
"result = model.{}({})".format(
check.nsca_function, check.nsca_args or ""
),
results,
mode="exec",
nocopy=True,
)
result = results["result"]
if not result:
if check.allow_void_result:
return False
raise ValueError("'%s' method does not return" % check.nsca_function)
if len(result) == 2:
rc, message = result
else:
rc, message, performance = result
except Exception as exc:
rc, message = 2, "%s" % exc
_logger.warning("%s - %s", check.service, message)
check._send_nsca(rc, message, performance)
return True
def _send_nsca(self, rc, message, performance):
for check in self:
check.server_id._send_nsca(check.service, rc, message, performance)

View file

@ -0,0 +1,236 @@
# (Copyright) 2015 ABF OSIELL <http://osiell.com>
# (Copyright) 2018 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import errno
import logging
import os
import shlex
import subprocess
import psutil
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools import config
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
_logger = logging.getLogger(__name__)
SEND_NSCA_BIN = "/usr/sbin/send_nsca"
class NscaServer(models.Model):
_name = "nsca.server"
_description = "NSCA Server"
name = fields.Char("Hostname", required=True)
port = fields.Integer(default=5667, required=True)
password = fields.Char()
encryption_method = fields.Selection(
selection="_selection_encryption_method",
string="Encryption method",
default="1",
required=True,
)
config_dir_path = fields.Char(
"Configuration directory", compute="_compute_config_dir_path"
)
config_file_path = fields.Char(
"Configuration file", compute="_compute_config_file_path"
)
node_hostname = fields.Char(
"Hostname of this node",
required=True,
help="This is the hostname of the current Odoo node declared in the "
"monitoring server.",
)
check_ids = fields.One2many("nsca.check", "server_id", string="Checks")
check_count = fields.Integer(compute="_compute_check_count")
@api.depends("check_ids")
def _compute_check_count(self):
for r in self:
r.check_count = len(r.check_ids)
def _selection_encryption_method(self):
return [
("0", "0 - None (Do NOT use this option)"),
("1", "1 - Simple XOR"),
("2", "2 - DES"),
("3", "3 - 3DES (Triple DES)"),
("4", "4 - CAST-128"),
("5", "5 - CAST-256"),
("6", "6 - xTEA"),
("7", "7 - 3WAY"),
("8", "8 - BLOWFISH"),
("9", "9 - TWOFISH"),
("10", "10 - LOKI97"),
("11", "11 - RC2"),
("12", "12 - ARCFOUR"),
("14", "14 - RIJNDAEL-128"),
("15", "15 - RIJNDAEL-192"),
("16", "16 - RIJNDAEL-256"),
("19", "19 - WAKE"),
("20", "20 - SERPENT"),
("22", "22 - ENIGMA (Unix crypt)"),
("23", "23 - GOST"),
("24", "24 - SAFER64"),
("25", "25 - SAFER128"),
("26", "26 - SAFER+"),
]
def _compute_config_dir_path(self):
for server in self:
data_dir_path = config.get("data_dir")
dir_path = os.path.join(data_dir_path, "nsca_client", self.env.cr.dbname)
server.config_dir_path = dir_path
def _compute_config_file_path(self):
for server in self:
file_name = "send_nsca_%s.cfg" % server.id
full_path = os.path.join(server.config_dir_path, file_name)
server.config_file_path = full_path
def write_config_file(self):
for server in self:
try:
os.makedirs(server.config_dir_path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
with open(server.config_file_path, "w") as config_file:
if server.password:
config_file.write("password=%s\n" % server.password)
config_file.write("encryption_method=%s\n" % server.encryption_method)
return True
def write(self, vals):
res = super(NscaServer, self).write(vals)
self.write_config_file()
return res
@api.model
def create(self, vals):
res = super(NscaServer, self).create(vals)
res.write_config_file()
return res
@api.model
def current_status(self):
ram = 0
cpu = 0
if psutil:
process = psutil.Process(os.getpid())
# psutil changed its api through versions
processes = [process]
if config.get("workers") and process.parent: # pragma: no cover
if callable(process.parent):
process = process.parent()
else:
process = process.parent
if hasattr(process, "children"):
processes += process.children(True)
elif hasattr(process, "get_children"):
processes += process.get_children(True)
for process in processes:
if hasattr(process, "memory_percent"):
ram += process.memory_percent()
if hasattr(process, "cpu_percent"):
cpu += process.cpu_percent(interval=1)
user_count = 0
if "bus.presence" in self.env.registry:
user_count = self.env["bus.presence"].search_count(
[("status", "=", "online")]
)
performance = {
"cpu": {"value": cpu},
"ram": {"value": ram},
"user_count": {"value": user_count},
}
return 0, "OK", performance
def _prepare_command(self):
"""Prepare the shell command used to send the check result
to the NSCA daemon.
"""
cmd = "/usr/sbin/send_nsca -H {} -p {} -c {}".format(
self.name,
self.port,
self.config_file_path,
)
return shlex.split(cmd)
@api.model
def _run_command(self, cmd, check_result):
"""Send the check result through the '/usr/sbin/send_nsca' command."""
try:
proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
stdout = proc.communicate(input=check_result)[0]
_logger.debug("%s: %s", check_result, stdout.strip())
except Exception as exc:
_logger.error(exc)
def _check_send_nsca_command(self):
"""Check if the NSCA client is installed."""
if not is_exe(SEND_NSCA_BIN):
raise UserError(
_(
"Command '%s' not found. Please install the NSCA client.\n"
"On Debian/Ubuntu: apt-get install nsca-client"
)
% (SEND_NSCA_BIN)
)
def _format_check_result(self, service, rc, message):
"""Format the check result with tabulations as delimiter."""
message = message.replace("\t", " ")
hostname = self.node_hostname
check_result = "{}\t{}\t{}\t{}".format(hostname, service, rc, message)
return check_result.encode("utf-8")
def _send_nsca(self, service, rc, message, performance):
"""Send the result of the check to the NSCA daemon."""
msg = message
if len(performance) > 0:
msg += "| " + "".join(
[
"%s=%s%s;%s;%s;%s;%s"
% (
key,
performance[key]["value"],
performance[key].get("uom", ""),
performance[key].get("warn", ""),
performance[key].get("crit", ""),
performance[key].get("min", ""),
performance[key].get("max", ""),
)
for key in sorted(performance)
]
)
check_result = self._format_check_result(service, rc, msg)
cmd = self._prepare_command()
self._run_command(cmd, check_result)
def show_checks(self):
self.ensure_one()
result = self.env["ir.actions.act_window"]._for_xml_id(
"nsca_client.action_nsca_check_tree"
)
context = {"default_server_id": self.id}
result["context"] = context
result["domain"] = [("server_id", "=", self.id)]
if len(self.check_ids) == 1:
res = self.env.ref("nsca_client.view_nsca_check_form", False)
result["views"] = [(res and res.id or False, "form")]
result["res_id"] = self.check_ids.id
return result