Browse Source

Merge pull request #1280 from etobella/11.0-mig-nsca_client

[11.0] nsca client
pull/1414/head
Jordi Ballester Alomar 6 years ago
committed by GitHub
parent
commit
c6103a3be1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .travis.yml
  2. 126
      nsca_client/README.rst
  3. 4
      nsca_client/__init__.py
  4. 22
      nsca_client/__manifest__.py
  5. 22
      nsca_client/demo/demo_data.xml
  6. 225
      nsca_client/i18n/fr.po
  7. 192
      nsca_client/i18n/nsca_client.pot
  8. 1
      nsca_client/models/__init__.py
  9. 108
      nsca_client/models/nsca_check.py
  10. 239
      nsca_client/models/nsca_server.py
  11. 3
      nsca_client/security/ir.model.access.csv
  12. BIN
      nsca_client/static/description/check.png
  13. BIN
      nsca_client/static/description/icon.png
  14. BIN
      nsca_client/static/description/server.png
  15. 1
      nsca_client/tests/__init__.py
  16. 104
      nsca_client/tests/test_nsca.py
  17. 90
      nsca_client/views/nsca_check.xml
  18. 12
      nsca_client/views/nsca_menu.xml
  19. 63
      nsca_client/views/nsca_server.xml

1
.travis.yml

@ -12,6 +12,7 @@ addons:
packages:
- expect-dev # provides unbuffer utility
- python-lxml # because pip installation is slow
- nsca-client
env:
global:

126
nsca_client/README.rst

@ -0,0 +1,126 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
===========
NSCA Client
===========
This is a technical module to send passive alerts to your favorite NSCA daemon
(Nagios, Shinken...).
This module is based on the Odoo cron system and requires a NSCA client
installed on the system to satisfy the ``/usr/sbin/send_nsca`` command.
Installation
============
To use this module, you need to install a NSCA client.
On Debian/Ubuntu::
$ sudo apt-get install nsca-client
Configuration
=============
To configure this module, you need to:
* Configure your server and a passive service in your monitoring tool
(e.g service ``Odoo Mail Queue`` on host ``MY-SERVER``).
* Declare your NSCA server in the menu Configuration / Technical / NSCA Client / Servers
.. image:: nsca_client/static/description/server.png
:width: 400 px
* Create NSCA checks in the menu Configuration / Technical / NSCA Client / Checks
.. image:: nsca_client/static/description/check.png
:width: 400 px
* Code the methods which will be called by the NSCA checks.
Such methods must return a tuple ``(RC, MESSAGE, PERFORMANCE_DATA)`` where ``RC`` is an integer,
``MESSAGE`` a unicode string AND ``PERFOMANCE_DATA`` is a dictionary.
``RC`` values and the corresponding status are:
- 0: OK
- 1: WARNING
- 2: CRITICAL
- 3: UNKNOWN
``PERFORMANCE_DATA`` is not mandatory, so it could be possible to send
``(RC, MESSAGE)``.
Each element of ``PERFORMANCE_DATA`` will be a dictionary that could contain:
- value: value of the data (required)
- max: Max value on the chart
- min: Minimum value on the chart
- warn: Warning value on the chart
- crit: Critical value on the chart
- uom: Unit of Measure on the chart (s - Seconds, % - Percentage, B - Bytes, c - Continuous)
The key of the dictionary will be used as the performance_data label.
E.g:
.. code-block:: python
class MailMail(models.Model):
_inherit = 'mail.mail'
@api.model
def nsca_check_mails(self):
mails = self.search([('state', '=', 'exception')])
if mails:
return (1, u"%s mails not sent" % len(mails), {
'exceptions': {'value': len(mails)}})
return (0, u"OK", {'exceptions': {'value': len(mails)}})
On the example, the performance data will use the label ``exceptions`` and the
value will be the number of exception of mails.
Usage
=====
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/149/11.0
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/server-tools/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed feedback.
Credits
=======
Images
------
* Daniel Foré: `Icon <http://www.iconarchive.com/show/elementary-icons-by-danrabbit/Apps-system-monitor-icon.html>`_ (Elementary theme, GPL).
Contributors
------------
* Sébastien Alix <sebastien.alix@osiell.com>
* Enric Tobella <etobella@creublanca.es>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.

4
nsca_client/__init__.py

@ -0,0 +1,4 @@
# © 2015 ABF OSIELL <http://osiell.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models

22
nsca_client/__manifest__.py

@ -0,0 +1,22 @@
# © 2015 ABF OSIELL <http://osiell.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "NSCA Client",
"summary": "Send passive alerts to monitor your Odoo application.",
"version": "11.0.1.0.0",
"category": "Tools",
"website": "http://github.com/OCA/server-tools",
"author": "ABF OSIELL, Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"data": [
"security/ir.model.access.csv",
"views/nsca_menu.xml",
"views/nsca_check.xml",
"views/nsca_server.xml",
],
"demo": [
"demo/demo_data.xml",
],
}

22
nsca_client/demo/demo_data.xml

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="nsca_server_default" model="nsca.server">
<field name="name">nagios.example.net</field>
<field name="port">5667</field>
<field name="node_hostname">MY-SERVER</field>
</record>
<record id="demo_nsca_check_mails" model="nsca.check">
<field name="server_id" ref="nsca_server_default"/>
<field name="service">Odoo Mail Queue</field>
<field name="interval_number" eval="10"/>
<field name="interval_type">minutes</field>
<field name="nsca_model">mail.mail</field>
<field name="nsca_function">nsca_check_mails</field>
<field name="nsca_args"></field>
</record>
</data>
</odoo>

225
nsca_client/i18n/fr.po

@ -0,0 +1,225 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * nsca_client
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-07 12:33+0000\n"
"PO-Revision-Date: 2016-04-07 12:33+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "(1, u\"3 mails not sent\")"
msgstr "(1, u\"3 mails non-envoyés\")"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "0: OK"
msgstr "0: OK"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "1: WARNING"
msgstr "1: WARNING"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "2: CRITICAL"
msgstr "2: CRITICAL"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "3: UNKNOWN"
msgstr "3: UNKNOWN"
#. module: nsca_client
#: field:nsca.check,allow_void_result:0
msgid "Allow void result"
msgstr "Autoriser l'absence de résultat"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "Any other RC value will be treated as CRITICAL."
msgstr "Tout autre valeur RC sera traitée comme CRITICAL."
#. module: nsca_client
#: field:nsca.check,nsca_args:0
msgid "Arguments"
msgstr "Arguments"
#. module: nsca_client
#: help:nsca.check,allow_void_result:0
msgid "By default, a CRITICAL message is sent if the method does not return.\n"
"If checked, no message will be sent in such a case."
msgstr "Par défaut, un message de niveau CRITICAL sera envoyé si la méthode ne retourne aucun résultat.\n"
"Si cette option est cochée, aucun message ne sera envoyé dans un tel cas."
#. module: nsca_client
#: model:ir.actions.act_window,name:nsca_client.action_nsca_check_tree
#: model:ir.ui.menu,name:nsca_client.menu_action_nsca_check_tree
#: view:nsca.server:nsca_client.view_nsca_server_form
#: field:nsca.server,check_ids:0
msgid "Checks"
msgstr "Contrôles"
#. module: nsca_client
#: code:addons/nsca_client/models/nsca_check.py:154
#, python-format
msgid "Command '%s' not found. Please install the NSCA client.\n"
"On Debian/Ubuntu: apt-get install nsca-client"
msgstr "Commande '%s' non-disponible. Veuillez installer le client NSCA.\n"
"Sur Debian/Ubuntu: apt-get install nsca-client"
#. module: nsca_client
#: field:nsca.check,create_uid:0
#: field:nsca.server,create_uid:0
msgid "Created by"
msgstr "Créé par"
#. module: nsca_client
#: field:nsca.check,create_date:0
#: field:nsca.server,create_date:0
msgid "Created on"
msgstr "Créé le"
#. module: nsca_client
#: field:nsca.check,cron_id:0
msgid "Cron"
msgstr "Cron"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "E.g."
msgstr "Ex :"
#. module: nsca_client
#: field:nsca.server,encryption_method:0
msgid "Encryption method"
msgstr "Méthode de chiffrement"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "Frequency"
msgstr "Fréquence"
#. module: nsca_client
#: field:nsca.server,name:0
msgid "Hostname"
msgstr "Serveur"
#. module: nsca_client
#: field:nsca.server,node_hostname:0
msgid "Hostname of this node"
msgstr "Nom d'hôte du noeud"
#. module: nsca_client
#: field:nsca.check,id:0
#: field:nsca.server,id:0
msgid "ID"
msgstr "ID"
#. module: nsca_client
#: field:nsca.check,write_uid:0
#: field:nsca.server,write_uid:0
msgid "Last Updated by"
msgstr "Dernière modification par"
#. module: nsca_client
#: field:nsca.check,write_date:0
#: field:nsca.server,write_date:0
msgid "Last Updated on"
msgstr "Dernière mise à jour le"
#. module: nsca_client
#: field:nsca.check,nsca_function:0
msgid "Method"
msgstr "Méthode"
#. module: nsca_client
#: field:nsca.check,nsca_model:0
msgid "Model"
msgstr "Modèle"
#. module: nsca_client
#: code:addons/nsca_client/models/nsca_check.py:64
#: model:ir.model,name:nsca_client.model_nsca_check
#: view:nsca.check:nsca_client.view_nsca_check_form
#, python-format
msgid "NSCA Check"
msgstr "Contrôle NSCA"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_tree
msgid "NSCA Checks"
msgstr "Contrôles NSCA"
#. module: nsca_client
#: model:ir.ui.menu,name:nsca_client.menu_nsca_client
msgid "NSCA Client"
msgstr "Client NSCA"
#. module: nsca_client
#: model:ir.model,name:nsca_client.model_nsca_server
#: view:nsca.server:nsca_client.view_nsca_server_form
msgid "NSCA Server"
msgstr "Serveur NSCA"
#. module: nsca_client
#: view:nsca.server:nsca_client.view_nsca_server_tree
msgid "NSCA Servers"
msgstr "Serveurs NSCA"
#. module: nsca_client
#: view:nsca.server:nsca_client.view_nsca_server_form
msgid "Node identity"
msgstr "Identité du noeud"
#. module: nsca_client
#: field:nsca.server,password:0
msgid "Password"
msgstr "Mot de passe"
#. module: nsca_client
#: field:nsca.server,port:0
msgid "Port"
msgstr "Port"
#. module: nsca_client
#: field:nsca.check,server_id:0
msgid "Server"
msgstr "Serveur"
#. module: nsca_client
#: model:ir.actions.act_window,name:nsca_client.action_nsca_server_tree
#: model:ir.ui.menu,name:nsca_client.menu_action_nsca_server_tree
msgid "Servers"
msgstr "Serveurs"
#. module: nsca_client
#: field:nsca.check,service:0
msgid "Service"
msgstr "Service"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "Settings"
msgstr "Paramètres"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "The method must return a tuple (RC, MESSAGE) where RC is an integer:"
msgstr "La méthode doit retourner un tuple (RC, MESSAGE) où RC est un entier :"
#. module: nsca_client
#: help:nsca.server,node_hostname:0
msgid "This is the hostname of the current Odoo node declared in the monitoring server."
msgstr "C'est le nom d'hôte identifiant le serveur Odoo dans la configuration du serveur NSCA."

192
nsca_client/i18n/nsca_client.pot

@ -0,0 +1,192 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * nsca_client
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-12-17 07:05+0000\n"
"PO-Revision-Date: 2015-12-17 07:05+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "(1, u\"3 mails not sent\")"
msgstr ""
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "0: OK"
msgstr ""
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "1: WARNING"
msgstr ""
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "2: CRITICAL"
msgstr ""
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "3: UNKNOWN"
msgstr ""
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "Any other RC value will be treated as CRITICAL."
msgstr ""
#. module: nsca_client
#: field:nsca.check,nsca_args:0
msgid "Arguments"
msgstr ""
#. module: nsca_client
#: model:ir.actions.act_window,name:nsca_client.action_nsca_check_tree
#: model:ir.ui.menu,name:nsca_client.menu_action_nsca_check_tree
#: view:nsca.server:nsca_client.view_nsca_server_form
#: field:nsca.server,check_ids:0
msgid "Checks"
msgstr ""
#. module: nsca_client
#: code:addons/nsca_client/models/nsca_check.py:145
#, python-format
msgid "Command '%s' not found. Please install the NSCA client.\n"
"On Debian/Ubuntu: apt-get install nsca-client"
msgstr ""
#. module: nsca_client
#: field:nsca.server,config_file_path:0
msgid "Configuration file"
msgstr ""
#. module: nsca_client
#: field:nsca.check,create_uid:0
#: field:nsca.server,create_uid:0
msgid "Created by"
msgstr ""
#. module: nsca_client
#: field:nsca.check,create_date:0
#: field:nsca.server,create_date:0
msgid "Created on"
msgstr ""
#. module: nsca_client
#: field:nsca.check,cron_id:0
msgid "Cron"
msgstr ""
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "E.g."
msgstr ""
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "Frequency"
msgstr ""
#. module: nsca_client
#: field:nsca.server,name:0
msgid "Hostname"
msgstr ""
#. module: nsca_client
#: field:nsca.check,id:0
#: field:nsca.server,id:0
msgid "ID"
msgstr ""
#. module: nsca_client
#: field:nsca.check,write_uid:0
#: field:nsca.server,write_uid:0
msgid "Last Updated by"
msgstr ""
#. module: nsca_client
#: field:nsca.check,write_date:0
#: field:nsca.server,write_date:0
msgid "Last Updated on"
msgstr ""
#. module: nsca_client
#: field:nsca.check,nsca_function:0
msgid "Method"
msgstr ""
#. module: nsca_client
#: field:nsca.check,nsca_model:0
msgid "Model"
msgstr ""
#. module: nsca_client
#: code:addons/nsca_client/models/nsca_check.py:60
#: model:ir.model,name:nsca_client.model_nsca_check
#: view:nsca.check:nsca_client.view_nsca_check_form
#, python-format
msgid "NSCA Check"
msgstr ""
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_tree
msgid "NSCA Checks"
msgstr ""
#. module: nsca_client
#: model:ir.ui.menu,name:nsca_client.menu_nsca_client
msgid "NSCA Client"
msgstr ""
#. module: nsca_client
#: model:ir.model,name:nsca_client.model_nsca_server
#: view:nsca.server:nsca_client.view_nsca_server_form
msgid "NSCA Server"
msgstr ""
#. module: nsca_client
#: view:nsca.server:nsca_client.view_nsca_server_tree
msgid "NSCA Servers"
msgstr ""
#. module: nsca_client
#: field:nsca.server,port:0
msgid "Port"
msgstr ""
#. module: nsca_client
#: field:nsca.check,server_id:0
msgid "Server"
msgstr ""
#. module: nsca_client
#: model:ir.actions.act_window,name:nsca_client.action_nsca_server_tree
#: model:ir.ui.menu,name:nsca_client.menu_action_nsca_server_tree
msgid "Servers"
msgstr ""
#. module: nsca_client
#: field:nsca.check,service:0
msgid "Service"
msgstr ""
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "Settings"
msgstr ""
#. module: nsca_client
#: view:nsca.check:nsca_client.view_nsca_check_form
msgid "The method must return a tuple (RC, MESSAGE) where RC is an integer:"
msgstr ""

1
nsca_client/models/__init__.py

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

108
nsca_client/models/nsca_check.py

@ -0,0 +1,108 @@
# (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 = u"NSCA Check"
_inherits = {'ir.cron': 'cron_id'}
cron_id = fields.Many2one(
'ir.cron', string=u"Cron",
required=True, ondelete='cascade', readonly=True)
server_id = fields.Many2one(
'nsca.server', string=u"Server", required=True)
service = fields.Char(u"Service", required=True)
nsca_model = fields.Char(u"Model")
nsca_function = fields.Char(u"Method")
nsca_args = fields.Char(u"Arguments")
allow_void_result = fields.Boolean(
u"Allow void result", default=False,
help=u"By default, a CRITICAL message is sent if the method does not "
u"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
@api.multi
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': u"%s - %s" % (_(u"NSCA Check"), check.service),
'model_id': model.id,
'state': 'code',
'code': 'model._cron_check(%s,)' % check.id,
'doall': False,
'numbercall': -1
}
super(NscaCheck, check).write(vals)
@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
@api.multi
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.%s(%s)' % (
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
@api.multi
def _send_nsca(self, rc, message, performance):
for check in self:
check.server_id._send_nsca(check.service, rc, message, performance)

239
nsca_client/models/nsca_server.py

@ -0,0 +1,239 @@
# (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 psutil
import os
import shlex
import subprocess
import logging
from odoo import api, fields, models, _
from odoo.tools import config
from odoo.exceptions import UserError
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 = u"NSCA Server"
name = fields.Char(u"Hostname", required=True)
port = fields.Integer(u"Port", default=5667, required=True)
password = fields.Char(u"Password")
encryption_method = fields.Selection(
selection='_selection_encryption_method',
string=u"Encryption method", default='1', required=True)
config_dir_path = fields.Char(
u"Configuration directory",
compute='_compute_config_dir_path')
config_file_path = fields.Char(
u"Configuration file",
compute='_compute_config_file_path')
node_hostname = fields.Char(
u"Hostname of this node", required=True,
help=u"This is the hostname of the current Odoo node declared in the "
u"monitoring server.")
check_ids = fields.One2many(
'nsca.check', 'server_id', string=u"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', u"0 - None (Do NOT use this option)"),
('1', u"1 - Simple XOR"),
('2', u"2 - DES"),
('3', u"3 - 3DES (Triple DES)"),
('4', u"4 - CAST-128"),
('5', u"5 - CAST-256"),
('6', u"6 - xTEA"),
('7', u"7 - 3WAY"),
('8', u"8 - BLOWFISH"),
('9', u"9 - TWOFISH"),
('10', u"10 - LOKI97"),
('11', u"11 - RC2"),
('12', u"12 - ARCFOUR"),
('14', u"14 - RIJNDAEL-128"),
('15', u"15 - RIJNDAEL-192"),
('16', u"16 - RIJNDAEL-256"),
('19', u"19 - WAKE"),
('20', u"20 - SERPENT"),
('22', u"22 - ENIGMA (Unix crypt)"),
('23', u"23 - GOST"),
('24', u"24 - SAFER64"),
('25', u"25 - SAFER128"),
('26', u"26 - SAFER+"),
]
@api.multi
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
@api.multi
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
@api.multi
def write_config_file(self):
for server in self:
try:
os.makedirs(server.config_dir_path)
except OSError as exception:
if exception.errno != os.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
@api.multi
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 hasattr(process.parent, '__call__'):
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, u"OK", performance
@api.multi
def _prepare_command(self):
"""Prepare the shell command used to send the check result
to the NSCA daemon.
"""
cmd = u"/usr/sbin/send_nsca -H %s -p %s -c %s" % (
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(
_(u"Command '%s' not found. Please install the NSCA client.\n"
u"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 = u"%s\t%s\t%s\t%s" % (
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)
@api.multi
def show_checks(self):
self.ensure_one()
action = self.env.ref('nsca_client.action_nsca_check_tree')
result = action.read()[0]
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

3
nsca_client/security/ir.model.access.csv

@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_nsca_check,access_nsca_check,model_nsca_check,base.group_erp_manager,1,1,1,1
access_nsca_server,access_nsca_server,model_nsca_server,base.group_erp_manager,1,1,1,1

BIN
nsca_client/static/description/check.png

After

Width: 707  |  Height: 448  |  Size: 43 KiB

BIN
nsca_client/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 9.2 KiB

BIN
nsca_client/static/description/server.png

After

Width: 653  |  Height: 521  |  Size: 32 KiB

1
nsca_client/tests/__init__.py

@ -0,0 +1 @@
from . import test_nsca

104
nsca_client/tests/test_nsca.py

@ -0,0 +1,104 @@
# Copyright 2018 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import mock
from odoo.tests.common import TransactionCase
class Popen:
def __init__(self, cmd, stdout, stdin, stderr):
self.cmd = cmd
self.stdout = stdout
self.stdin = stdin
self.stderr = stderr
def communicate(input):
return ['test']
class TestNsca(TransactionCase):
def test_nsca(self):
server = self.env['nsca.server'].create({
'name': 'localhost',
'password': 'pass',
'encryption_method': '3',
'node_hostname': 'odoodev',
})
self.assertTrue(server.config_file_path)
with mock.patch('subprocess.Popen') as post:
post.return_value = Popen
check = self.env['nsca.check'].create({
'server_id': server.id,
'service': 'test',
'nsca_model': 'nsca.server',
'nsca_function': 'current_status'
})
self.assertTrue(check.model_id)
self.env['nsca.check']._cron_check(check.id,)
def test_write(self):
server = self.env['nsca.server'].create({
'name': 'localhost',
'password': 'pass',
'encryption_method': '3',
'node_hostname': 'odoodev',
})
self.assertTrue(server.config_file_path)
check = self.env['nsca.check'].create({
'server_id': server.id,
'service': 'test',
'nsca_model': 'nsca.server',
'nsca_function': 'current_status'
})
check.cron_id.state = 'object_create'
check.write({'interval_number': 1})
self.assertEqual(check.cron_id.state, 'object_create')
check.write({'service': 'change'})
self.assertNotEqual(check.cron_id.state, 'object_create')
def test_void_failure(self):
server = self.env['nsca.server'].create({
'name': 'localhost',
'password': 'pass',
'encryption_method': '3',
'node_hostname': 'odoodev',
})
check = self.env['nsca.check'].create({
'server_id': server.id,
'service': 'test',
'nsca_model': 'nsca.server',
'allow_void_result': False,
'nsca_function': '_check_send_nsca_command'
})
with mock.patch('subprocess.Popen') as post:
post.return_value = Popen
self.env['nsca.check']._cron_check(check.id,)
post.assert_called_once()
def test_void_ok(self):
server = self.env['nsca.server'].create({
'name': 'localhost',
'password': 'pass',
'encryption_method': '3',
'node_hostname': 'odoodev',
})
self.assertEqual(server.check_count, 0)
check = self.env['nsca.check'].create({
'server_id': server.id,
'service': 'test',
'nsca_model': 'nsca.server',
'allow_void_result': True,
'nsca_function': '_check_send_nsca_command'
})
self.assertEqual(server.check_count, 1)
action = server.show_checks()
self.assertEqual(check, self.env['nsca.check'].browse(
action['res_id']))
self.assertEqual(check, self.env['nsca.check'].search(
action['domain']))
with mock.patch('subprocess.Popen') as post:
post.return_value = Popen
self.env['nsca.check']._cron_check(check.id,)
post.assert_not_called()

90
nsca_client/views/nsca_check.xml

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2015 ABF OSIELL <http://osiell.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<data>
<record id="view_nsca_check_form" model="ir.ui.view">
<field name="name">nsca.check.form</field>
<field name="model">nsca.check</field>
<field name="arch" type="xml">
<form string="NSCA Check">
<sheet>
<group>
<group string="NSCA Check">
<field name="server_id"/>
<field name="service"/>
<label for="interval_number"
string="Frequency"/>
<div>
<field name="interval_number"
class="oe_inline"/>
<field name="interval_type"
class="oe_inline"/>
</div>
<field name="nextcall"/>
<field name="active"/>
</group>
<group string="Settings">
<field name="nsca_model"/>
<field name="nsca_function"/>
<field name="nsca_args" widget="ace" options="{'mode': 'python'}" />
<field name="allow_void_result"/>
<div colspan="2">
<p>The method must return a tuple (RC,
MESSAGE) where RC is an integer:
</p>
<newline/>
<ul>
<li>0: OK</li>
<li>1: WARNING</li>
<li>2: CRITICAL</li>
<li>3: UNKNOWN</li>
</ul>
<newline/>
<p>Any other RC value will be treated as
CRITICAL.
</p>
<p>E.g.
<em>(1, u"3 mails not sent")</em>
</p>
</div>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_nsca_check_tree" model="ir.ui.view">
<field name="name">nsca.check.tree</field>
<field name="model">nsca.check</field>
<field name="arch" type="xml">
<tree string="NSCA Checks" colors="gray: active==False">
<field name="service"/>
<field name="server_id"/>
<field name="nextcall"/>
<field name="active"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_nsca_check_tree">
<field name="name">Checks</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">nsca.check</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_nsca_check_tree"/>
<field name="context" eval="{'default_active': True}"/>
<field name="domain">['|', ('active', '=', True), ('active', '=',
False)]
</field>
</record>
<menuitem id="menu_action_nsca_check_tree"
parent="menu_nsca_client"
action="action_nsca_check_tree"/>
</data>
</odoo>

12
nsca_client/views/nsca_menu.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2015 ABF OSIELL <http://osiell.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<data>
<menuitem id="menu_nsca_client"
parent="base.menu_custom"
name="NSCA Client"/>
</data>
</odoo>

63
nsca_client/views/nsca_server.xml

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2015 ABF OSIELL <http://osiell.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<data>
<record id="view_nsca_server_form" model="ir.ui.view">
<field name="name">nsca.server.form</field>
<field name="model">nsca.server</field>
<field name="arch" type="xml">
<form string="NSCA Server">
<sheet>
<div class="oe_button_box" name="button_box">
<button name="show_checks" type="object"
class="oe_stat_button"
icon="fa-check-square">
<field name="check_count" widget="statinfo"
string="Checks"/>
<field name="check_ids" invisible="1"/>
</button>
</div>
<group string="NSCA Server">
<field name="name" style="width: 30%;"/>
<field name="port"/>
<field name="password" password="1"/>
<field name="encryption_method"/>
<field name="config_file_path"/>
</group>
<group string="Node identity">
<field name="node_hostname"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_nsca_server_tree" model="ir.ui.view">
<field name="name">nsca.server.tree</field>
<field name="model">nsca.server</field>
<field name="arch" type="xml">
<tree string="NSCA Servers">
<field name="name"/>
<field name="port"/>
<field name="config_file_path"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_nsca_server_tree">
<field name="name">Servers</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">nsca.server</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_nsca_server_tree"/>
</record>
<menuitem id="menu_action_nsca_server_tree"
parent="menu_nsca_client"
action="action_nsca_server_tree"/>
</data>
</odoo>
Loading…
Cancel
Save