Commit 15ce4ad9 authored by Pavel Vainerman's avatar Pavel Vainerman

(netdata-plugin): Вариант на основе запуска uniset2-admin

parent 527661d2
......@@ -52,6 +52,7 @@ static struct option longopts[] =
{ "oinfo", required_argument, 0, 'p' },
{ "verbose", no_argument, 0, 'v' },
{ "quiet", no_argument, 0, 'q' },
{ "csv", required_argument, 0, 'z' },
{ NULL, 0, 0, 0 }
};
......@@ -117,6 +118,7 @@ static void usage()
print_help(36, "-t|--getChangedTime id1@node1,id2@node2,id3,.. ", "Получить время последнего изменения.\n");
print_help(36, "-v|--verbose", "Подробный вывод логов.\n");
print_help(36, "-q|--quiet", "Выводит только результат.\n");
print_help(36, "-z|--csv", "Вывести результат (getValue) в виде val1,val2,val3...\n");
cout << endl;
}
......@@ -129,6 +131,7 @@ static void usage()
// --------------------------------------------------------------------------------------
static bool verb = false;
static bool quiet = false;
static bool csv = false;
int main(int argc, char** argv)
{
......@@ -141,7 +144,7 @@ int main(int argc, char** argv)
while(1)
{
opt = getopt_long(argc, argv, "hc:beosfur:l:i::x:g:w:y:p:vq", longopts, &optindex);
opt = getopt_long(argc, argv, "hc:beosfur:l:i::x:g:w:y:p:vqz:", longopts, &optindex);
if( opt == -1 )
break;
......@@ -190,7 +193,10 @@ int main(int argc, char** argv)
break;
case 'g': //--getValue
case 'z': //--csv
{
if( opt == 'z' )
csv = true;
// cout<<"(main):received option --getValue='"<<optarg<<"'"<<endl;
auto conf = uniset_init(argc, argv, conffile);
UInterface ui(conf);
......@@ -666,9 +672,14 @@ int getValue( const string& args, UInterface& ui )
auto conf = ui.getConf();
auto sl = UniSetTypes::getSInfoList( args, conf );
if( csv )
quiet = true;
if( !quiet )
cout << "====== getValue ======" << endl;
size_t num = 0;
for( auto && it : sl )
{
try
......@@ -694,8 +705,19 @@ int getValue( const string& args, UInterface& ui )
if( !quiet )
cout << " value: " << ui.getValue(it.si.id, it.si.node) << endl;
else
{
if( csv )
{
// т.к. может сработать исключение, а нам надо вывести ','
// до числа, то сперва получаем val
long val = ui.getValue(it.si.id, it.si.node);
if( csv && num++ > 0 )
cout << ",";
cout << val;
}
else
cout << ui.getValue(it.si.id, it.si.node);
}
break;
default:
......
......@@ -11,6 +11,7 @@ ln -s -f admin.sh omap
ln -s -f admin.sh msgmap
ln -s -f admin.sh setValue
ln -s -f admin.sh getValue
ln -s -f admin.sh csv
ln -s -f admin.sh getRawValue
ln -s -f admin.sh getChangedTime
ln -s -f admin.sh getCalibrate
......
......@@ -9,6 +9,7 @@
#%def_enable modbus
%def_disable tests
%def_disable mqtt
%def_enable netdata
%define oname uniset2
......@@ -62,6 +63,10 @@ BuildRequires: librrd-devel
BuildRequires: libmosquitto-devel
%endif
%if_enabled netdata
BuildRequires: netdata
%endif
%if_enabled python
BuildRequires: python-devel python-module-distribute
BuildRequires(pre): rpm-build-python
......@@ -118,6 +123,16 @@ Requires: %name = %version-%release
Python interface for %name
%endif
%if_enabled netdata
%package netdata-plugin
Group: Development/Tools
Summary: python plugin for netdata
Requires: python-module-%oname
%description netdata-plugin
python plugin for netdata
%endif
%package utils
Summary: UniSet utilities
Group: Development/Tools
......@@ -385,6 +400,12 @@ mv -f %buildroot%python_sitelibdir_noarch/* %buildroot%python_sitelibdir/%oname
%python_sitelibdir/%oname/
%endif
%if_enabled netdata
%files netdata-plugin
%_libdir/netdata/python.d/*.*
%config(noreplace) %_sysconfdir/netdata/python.d/*.conf
%endif
%if_enabled docs
%files docs
%_docdir/%oname/
......
......@@ -5653,7 +5653,7 @@
<!-- https://github.com/firehol/netdata/wiki/External-Plugins -->
<!-- CHART type.id name title units [family [context [charttype [priority [update_every]]]]] -->
<chart id='unet' name='NAME' title="unet" units='count' family='UNET' context='' charttype='stacked' priority='' update_every=''>
<chart id='unet' name='NAME' title="unet" units='count' family='UNET' context='' charttype='line' priority='' update_every=''>
<!-- Чтобы иметь возможность выводить на одном чарте, разные группы можно указывать много 'line' -->
......
......@@ -451,6 +451,7 @@ AC_CONFIG_FILES([Makefile
testsuite/Makefile
python/lib/Makefile
python/lib/pyUniSet/Makefile
python/netdata-plugin/Makefile
python/Makefile])
......
if DISABLE_PYTHON
else
SUBDIRS=lib
SUBDIRS=lib netdata-plugin
include $(top_builddir)/include.mk
......
if DISABLE_PYTHON
else
netdataconfdir = $(sysconfdir)/netdata/python.d
netdataconf_DATA = *.conf
plugdir = $(libdir)/netdata/python.d
plug_DATA = *.py
include $(top_builddir)/include.mk
endif
/usr/lib/netdata/python.d/python_modules
\ No newline at end of file
/home/pv/Projects/uniset-2.0/conf/test.xml
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ----------------------------------------------------------------------------------------------------------
# Description: uniset netdata python.d module
# Author: Pavel Vainerman (pv)
# ----------------------------------------------------------------------------------------------------------
# Вариант на основе запуска uniset2-admin --сsv id1,id2,id3...
# ----------------------------------------------------------------------------------------------------------
# В configure.xml проекта ождается секция <netdata> описывающая
# charts и параметры.
# <netdata>
# <!-- https://github.com/firehol/netdata/wiki/External-Plugins -->
# <!-- CHART type.id name title units [family [context [charttype [priority [update_every]]]]] -->
# <chart id='unet' name='Temperature' title="Temperature" units='°С' context='' charttype='area' priority='' update_every=''>
#
# <!-- Чтобы иметь возможность выводить на одном чарте, разные группы можно указывать много 'line' -->
#
# <!-- Параметры берутся из <sensors> в виду netdata_xxx (необязательные помечены []
# В качестве id - берётся name.
# В качестве name - берётся name, если не указан netdata_name=''
# -->
# <!-- DIMENSION id [name [algorithm [multiplier [divisor [hidden]]]]] -->
# <lines filter_field='ndata' filter_value='temp'/>
# </chart>
# </netdata>
#
# TODO: можно сделать более оптимальный (по ресурсам) вариант со специальным UniSetNetDataServer (экономия на запуске admin каждые X секунд)
# ------------------------------------------------------------------------------------------------------------------
import os
import sys
import random
import uniset2
from uniset2 import UniXML
from uniset2 import UProxyObject
from uniset2 import UConnector
from subprocess import Popen, PIPE
sys.path.append("./python_modules")
from base import SimpleService
from base import ExecutableService
NAME = os.path.basename(__file__).replace(".chart.py", "")
# default module values
update_every = 5
priority = 90000
retries = 60
retries = 10000
class Service(SimpleService):
sensors = []
uproxy = None
uconnector = None
smOK = False
class Service(ExecutableService):
def __init__(self, configuration=None, name=None):
super(self.__class__, self).__init__(configuration=configuration, name=name)
conf = self.configuration.pop
confile = None
try:
confile = conf('confile')
except KeyError:
......@@ -43,36 +61,32 @@ class Service(SimpleService):
self.error("uniset plugin: Not found confile '%s'"%confile)
raise RuntimeError
#self.name = self.get_conf_param('name', name)
self.initOK = False
self.sensors = []
self.confile = confile
self.info("%s: read from %s"%(name,confile))
self.create_charts(confile)
self.init_uniset(confile)
# добавляем датчики в опрос..
for s in self.sensors:
self.uproxy.addToAsk(s[1])
def init_uniset(self, confile):
uniset_port = self.get_conf_param('port', '')
arglist= uniset2.Params_inst()
for i in range(0, len(sys.argv)):
if i >= uniset2.Params.max:
break;
arglist.add(sys.argv[i])
idlist = ''
num = 0
for nid,sid in self.sensors:
if num == 0:
idlist="%s"%str(sid)
num += 1
else:
idlist += ",%s"%str(sid)
port = self.get_conf_param('port', '')
if port != '':
p = '--uniset-port'
arglist.add_str(p)
arglist.add_str( str(port) )
uniset_command = self.get_conf_param('uniset_command',"/usr/bin/uniset2-admin --confile %s"%(self.confile))
uname = self.get_conf_param('uname', 'TestProc')
command = "%s --csv %s"%(uniset_command,idlist)
if uniset_port!=None and uniset_port!='':
command += " --uniset-port %s"%uniset_port
try:
self.uconnector = UConnector(arglist,confile)
self.uproxy = UProxyObject(uname)
except uniset2.UException, e:
self.error("uniset plugin: error: %s"% e.getError())
raise RuntimeError
self.configuration['command'] = command
self.command = command
self.info("%s: Check %d sensors. Update command: %s"%(name,len(self.sensors),command))
def get_conf_param(self, propname, defval):
try:
......@@ -86,7 +100,7 @@ class Service(SimpleService):
def find_section(self, xml, secname):
node = xml.findNode(xml.getDoc(), secname)[0]
if node == None:
self.error("not found '%s' section in %s" % (secname,xml.getFileName()))
self.error("not found section <%s> in confile '%s'" % (secname,xml.getFileName()))
raise RuntimeError
return node.children
......@@ -107,7 +121,7 @@ class Service(SimpleService):
# CHART type.id name title units [family [context [charttype [priority [update_every]]]]]
id = node.prop('id')
if id == '' or id == None:
self.error("IGNORE CHART.. Unknown id=''.")
self.error("IGNORE CHART.. Unknown id=''")
node = xml.nextNode(node)
continue
......@@ -204,7 +218,7 @@ class Service(SimpleService):
return False
if ff == '':
return True;
return True
if fv == '' and node.prop(ff) == '':
return False
......@@ -214,49 +228,74 @@ class Service(SimpleService):
return True
def check(self):
def _get_data(self):
data = {}
self.info("**** uniset_activate_objects")
# ret = super(self.__class__, self).check()
try:
self.uconnector.activate_objects()
except uniset2.UException, e:
self.error("%s"% e.getError())
raise False
raw = self._get_raw_data()
return True
if raw == None or len(raw) == 0:
if self.initOK == True:
return {}
def _get_data(self):
# забиваем нулями.. (нужно подумать, правильно ли это, можно сделать defaultValue в настройках)
self.initOK = True
for id, sid in self.sensors:
data[id] = 0
return data
data = {}
raw = raw[-1].split(',')
for netid,id in self.sensors:
data[netid] = self.uproxy.getValue(id)
if len(raw) < len(self.sensors):
if len(raw) > 0:
self.debug("_get_data ERROR: len data=%d < len sensors=%d"%(len(raw),len(self.sensors)))
return {}
if len(data) == 0:
return None
i = 0
for id,sid in self.sensors:
data[id] = raw[i]
i += 1
except (ValueError, AttributeError):
return {}
return data
def update(self, interval):
def _get_raw_data(self):
"""
Get raw data from executed command
:return: str
"""
try:
p = Popen(self.command, shell=True, stdout=PIPE, stderr=PIPE)
except Exception as e:
self.error("Executing command", self.command, "resulted in error:", str(e))
return None
if not self.uproxy.askIsOK() and not self.uproxy.reaskSensors():
return False
data = []
for line in p.stdout.readlines():
data.append(str(line.decode()))
prev_smOK = self.smOK
self.smOK = self.uproxy.smIsOK()
if len(data) == 0:
# self.error("No data collected.")
return None
if prev_smOK != self.smOK and self.smOK:
self.info("SM exist OK. Reask sensors..")
self.uproxy.reaskSensors()
return data
return super(self.__class__, self).update(interval)
def check(self):
# Считаем что у нас всегда, всё хорошо, даже если SM недоступна
return True
# def update(self, interval):
# super(self.__class__, self).update(interval)
# return True
if __name__ == "__main__":
config = {}
config['confile'] = './test.xml'
config['port'] = 2809
config['port'] = 53817
config['uname'] = 'TestProc'
config['update_every'] = update_every
config['priority'] = priority
......@@ -264,12 +303,12 @@ if __name__ == "__main__":
serv = Service(config,"test")
config2 = {}
config2['confile'] = './test.xml'
config2['port'] = 2809
config2['uname'] = 'TestProc1'
config2['update_every'] = update_every
config2['priority'] = priority
config2['retries'] = retries
serv2 = Service(config2,"test")
# config2 = {}
# config2['confile'] = './test.xml'
# config2['port'] = 52809
# config2['uname'] = 'TestProc1'
# config2['update_every'] = update_every
# config2['priority'] = priority
# config2['retries'] = retries
#
# serv2 = Service(config2,"test")
......@@ -67,20 +67,15 @@
# AUTO-DETECTION JOBS
# only one of them will run (they have the same name)
unet:
confile: /home/pv/Projects.com/uniset-2.0/conf/test.xml
name: utest
uname: TestProc
port: 53817
#project1t:
# confile: /path/to/project1/conf/configure.xml
# name: utest
# port: 53817
project2:
confile: /home/pv/Projects.com/uniset-2.0/conf/test.xml
name: project2
uname: TestProc1
port: 53817
#project2:
# confile: /path/to/project2/conf/configure.xml
# port: 53817
# uniset_command: /usr/bin/ctl-admin-project2.sh
project3:
confile: /home/pv/Projects.com/uniset-2.0/conf/test.xml
name: project3
uname: TestProc2
port: 53817
#project3:
# confile: /path/to/project2/conf/configure.xml
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment