Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
The container registry cleanup task is now completed and the registry can be used normally.
Open sidebar
dcdb
dcdb
Commits
62974ab6
Commit
62974ab6
authored
Jul 06, 2018
by
Micha Mueller
Browse files
Fill SNMP plugin with life
parent
797377ab
Changes
10
Hide whitespace changes
Inline
Side-by-side
Makefile
View file @
62974ab6
...
...
@@ -15,7 +15,7 @@ CXXFLAGS = -std=c++11 -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG -DBOOST_NETWORK_EN
LIBS
=
-L
../deps/mosquitto_build/lib
-L
$(DCDBDEPLOYPATH)
/lib/
-ldl
-lmosquitto
-lboost_system
-lboost_thread
-lboost_log_setup
-lboost_log
-lpthread
-lcrypto
-lssl
-lcppnetlib-server-parsers
-lcppnetlib-uri
-rdynamic
OBJS
=
src/dcdbpusher.o src/Configuration.o src/Sensor.o src/MQTTPusher.o src/HttpsServer.o
PLUGINS_BASE
=
libdcdbplugin_pdu libdcdbplugin_sysfs libdcdbplugin_ipmi libdcdbplugin_bacnet
PLUGINS_BASE
=
libdcdbplugin_pdu libdcdbplugin_sysfs libdcdbplugin_ipmi libdcdbplugin_bacnet
libdcdbplugin_snmp
ifeq
($(OS),Darwin)
BACNET_PORT
=
bsd
...
...
@@ -77,3 +77,6 @@ libdcdbplugin_pdu.$(LIBEXT): src/Sensor.o src/sensors/pdu/PDUSensor.o src/sensor
libdcdbplugin_bacnet.$(LIBEXT)
:
src/Sensor.o src/sensors/bacnet/BACnetSensor.o src/sensors/bacnet/BACnetClient.o src/sensors/bacnet/BACnetConfigurator.o
$(CXX)
$(LIBFLAGS)$@
-o
$@
$^
-L
$(DCDBDEPLOYPATH)
/lib/
-lboost_log
-lboost_system
-lbacnet
libdcdbplugin_snmp.$(LIBEXT)
:
src/Sensor.o src/sensors/snmp/SNMPSensor.o src/sensors/snmp/SNMPConnection.o src/sensors/snmp/SNMPConfigurator.o
$(CXX)
$(LIBFLAGS)$@
-o
$@
$^
-L
$(DCDBDEPLOYPATH)
/lib/
-lboost_log
-lboost_system
-lnetsnmp
-lnetsnmpagent
config/global.conf
View file @
62974ab6
...
...
@@ -26,6 +26,11 @@ restAPI {
plugins
{
plugin
snmp
{
path
./
config
}
plugin
sysfs
{
path
./
config
...
...
config/snmp.conf
0 → 100644
View file @
62974ab6
global
{
mqttprefix
/
00112233445566778899
AABBCC
}
templates
{
sensor
temp1
{
interval
1000
minValues
3
}
}
;
Connections
contains
a
list
of
connections
;
So
far
,
we
only
support
"Agent"
mode
in
which
we
connect
to
a
;
SNMP
agent
and
issue
GET
commands
to
read
the
data
.
connections
{
;
Each
connection
is
identified
by
a
unique
name
.
However
,
this
;
name
is
only
useful
when
we
print
error
messages
.
connection
name1
{
Type
Agent
;
Type
of
connection
Host
HostNameOfSNMPAgent
;
Hostname
of
the
SNMP
agent
Port
161
;
Port
of
the
SNMP
agent
Community
public
;
SNMP
community
string
OIDPrefix
1
.
3
.
6
.
1
.
4
.
1
.
1000
;
When
querying
OIDs
,
we
'
ll
;
always
use
this
prefix
mqttPart
BB
;
When
generating
MQTT
topics
,
;
we
'
ll
append
this
part
to
;
the
prefix
sensor
name1
{
OID
100
.
1
;
OID
of
the
sensor
mqttsuffix
0001
;
MQTT
suffix
of
the
sensor
interval
1000
;
Read
sensor
every
1000
ms
}
sensor
name2
{
OID
100
.
2
mqttsuffix
0002
default
temp1
}
}
connection
name2
{
Type
Agent
Host
HostNameOfSNMPAgent2
Port
161
Community
public
OIDPrefix
1
.
3
.
6
.
1
.
4
.
1
.
1000
.
15
mqttPart
CC
sensor
name1
{
OID
3
mqttsuffix
0017
interval
5000
}
}
}
src/HttpsServer.cpp
View file @
62974ab6
...
...
@@ -65,7 +65,8 @@ void HttpsServer::requestHandler::operator()(server::request const &request, ser
}
//split query part into the individual queries (key-value pairs)
{
{
//do not remove the enclosing brackets
//need to encapsulate this code block to keep queryStrs local
std
::
vector
<
std
::
string
>
queryStrs
;
boost
::
split
(
queryStrs
,
query
,
boost
::
is_any_of
(
";"
),
boost
::
token_compress_on
);
for
(
auto
&
key
:
queryStrs
)
{
...
...
src/sensors/snmp/SNMPConfigurator.cpp
View file @
62974ab6
...
...
@@ -9,22 +9,137 @@
#include
<boost/foreach.hpp>
#include
<boost/property_tree/info_parser.hpp>
#include
<boost/algorithm/string.hpp>
SNMPConfigurator
::
SNMPConfigurator
()
{
/
/ TODO Auto-generated constructor stub
/
* Initialize SNMP library */
init_snmp
(
"dcdbpusher_SNMPplugin"
);
}
SNMPConfigurator
::~
SNMPConfigurator
()
{
// TODO Auto-generated destructor stub
}
SNMPConfigurator
::~
SNMPConfigurator
()
{}
bool
SNMPConfigurator
::
readConfig
(
std
::
string
cfgPath
)
{
//TODO
Configurator
::
readConfig
(
cfgPath
);
boost
::
property_tree
::
iptree
cfg
;
boost
::
property_tree
::
read_info
(
cfgPath
,
cfg
);
std
::
string
mqttPartConnection
;
//read global variables (if present overwrite those from global.conf)
BOOST_FOREACH
(
boost
::
property_tree
::
iptree
::
value_type
&
global
,
cfg
.
get_child
(
"global"
))
{
if
(
boost
::
iequals
(
global
.
first
,
"mqttprefix"
))
{
_mqttPrefix
=
global
.
second
.
data
();
if
(
_mqttPrefix
[
_mqttPrefix
.
length
()
-
1
]
!=
'/'
)
{
_mqttPrefix
.
append
(
"/"
);
}
LOG
(
debug
)
<<
" Using own MQTT-Prefix "
<<
_mqttPrefix
;
}
else
if
(
boost
::
iequals
(
global
.
first
,
"cacheInterval"
))
{
_cacheInterval
=
stoul
(
global
.
second
.
data
());
LOG
(
debug
)
<<
" Using own caching interval "
<<
_cacheInterval
<<
" [s]"
;
_cacheInterval
*=
1000
;
}
else
{
LOG
(
error
)
<<
" Value
\"
"
<<
global
.
first
<<
"
\"
not recognized. Omitting..."
;
}
}
//read template sensors
BOOST_FOREACH
(
boost
::
property_tree
::
iptree
::
value_type
&
sensor
,
cfg
.
get_child
(
"templates"
))
{
if
(
boost
::
iequals
(
sensor
.
first
,
"sensor"
))
{
LOG
(
debug
)
<<
"Template Sensor
\"
"
<<
sensor
.
second
.
data
()
<<
"
\"
"
;
if
(
!
sensor
.
second
.
empty
())
{
SNMPSensor
snmpSensor
(
sensor
.
second
.
data
());
if
(
readSensor
(
snmpSensor
,
sensor
.
second
))
{
_templateSensors
.
insert
(
sensorMap_t
::
value_type
(
snmpSensor
.
getName
(),
snmpSensor
));
}
else
{
LOG
(
warning
)
<<
"Template sensor
\"
"
<<
sensor
.
second
.
data
()
<<
"
\"
has bad values! Ignoring..."
;
}
}
}
}
BOOST_FOREACH
(
boost
::
property_tree
::
iptree
::
value_type
&
connection
,
cfg
.
get_child
(
"connections"
))
{
if
(
boost
::
iequals
(
connection
.
first
,
(
"connection"
)))
{
LOG
(
debug
)
<<
"Connection "
<<
connection
.
second
.
data
();
_connections
.
push_back
(
SNMPConnection
());
SNMPConnection
&
conn
=
_connections
.
back
();
if
(
!
connection
.
second
.
empty
())
{
BOOST_FOREACH
(
boost
::
property_tree
::
iptree
::
value_type
&
c
,
connection
.
second
)
{
if
(
boost
::
iequals
(
c
.
first
,
"Type"
))
{
//TODO would be relevant if we would support more than just agent mode...
// at the moment we just ignore it, as it can be only "Agent" anyways
}
else
if
(
boost
::
iequals
(
c
.
first
,
"Host"
))
{
conn
.
setHost
(
c
.
second
.
data
());
}
else
if
(
boost
::
iequals
(
c
.
first
,
"Port"
))
{
conn
.
setPort
(
stoi
(
c
.
second
.
data
()));
}
else
if
(
boost
::
iequals
(
c
.
first
,
"Community"
))
{
conn
.
setSNMPCommunity
(
c
.
second
.
data
());
}
else
if
(
boost
::
iequals
(
c
.
first
,
"OIDPrefix"
))
{
conn
.
setOIDPrefix
(
c
.
second
.
data
());
}
else
if
(
boost
::
iequals
(
c
.
first
,
"mqttPart"
))
{
mqttPartConnection
=
c
.
second
.
data
();
if
(
mqttPartConnection
[
mqttPartConnection
.
length
()
-
1
]
!=
'/'
)
{
mqttPartConnection
.
append
(
"/"
);
}
}
else
if
(
boost
::
iequals
(
c
.
first
,
"sensor"
))
{
LOG
(
debug
)
<<
"Sensor
\"
"
<<
c
.
second
.
data
()
<<
"
\"
"
;
if
(
!
c
.
second
.
empty
())
{
std
::
string
name
=
connection
.
second
.
data
()
+
"_"
+
c
.
second
.
data
();
SNMPSensor
*
snmpSensor
=
new
SNMPSensor
(
name
);
//first check if default sensor is given
boost
::
optional
<
boost
::
property_tree
::
iptree
&>
defaultC
=
c
.
second
.
get_child_optional
(
"default"
);
if
(
defaultC
)
{
LOG
(
debug
)
<<
" Using
\"
"
<<
defaultC
.
get
().
data
()
<<
"
\"
as default."
;
sensorMap_t
::
iterator
it
=
_templateSensors
.
find
(
defaultC
.
get
().
data
());
if
(
it
!=
_templateSensors
.
end
())
{
*
snmpSensor
=
it
->
second
;
snmpSensor
->
setName
(
name
);
}
else
{
LOG
(
warning
)
<<
" Template sensor
\"
"
<<
defaultC
.
get
().
data
()
<<
"
\"
not found! Using standard values."
;
}
}
snmpSensor
->
setMqtt
(
_mqttPrefix
+
mqttPartConnection
);
snmpSensor
->
setConnection
(
&
conn
);
//read remaining values
if
(
readSensor
(
*
snmpSensor
,
c
.
second
))
{
_sensors
.
push_back
(
snmpSensor
);
}
else
{
LOG
(
warning
)
<<
" Sensor
\"
"
<<
c
.
second
.
data
()
<<
"
\"
has bad values! Ignoring..."
<<
std
::
endl
;
}
}
}
}
}
conn
.
init
();
}
}
return
true
;
}
bool
SNMPConfigurator
::
readSensor
(
SNMPSensor
&
sensor
,
boost
::
property_tree
::
iptree
&
config
)
{
//TODO
BOOST_FOREACH
(
boost
::
property_tree
::
iptree
::
value_type
&
val
,
config
)
{
if
(
boost
::
iequals
(
val
.
first
,
"interval"
))
{
sensor
.
setInterval
(
stoull
(
val
.
second
.
data
()));
}
else
if
(
boost
::
iequals
(
val
.
first
,
"mqttsuffix"
))
{
sensor
.
setMqtt
(
sensor
.
getMqtt
()
+
val
.
second
.
data
());
}
else
if
(
boost
::
iequals
(
val
.
first
,
"minValues"
))
{
sensor
.
setMinValues
(
stoull
(
val
.
second
.
data
()));
}
else
if
(
boost
::
iequals
(
val
.
first
,
"OID"
))
{
sensor
.
setOID
(
sensor
.
getConnection
()
->
getOIDPrefix
()
+
"."
+
val
.
second
.
data
());
}
else
if
(
boost
::
iequals
(
val
.
first
,
"default"
))
{
//avoid unnecessary "Value not recognized" message
}
else
{
LOG
(
warning
)
<<
" Value
\"
"
<<
val
.
first
<<
"
\"
not recognized. Omitting..."
;
}
}
sensor
.
setCacheInterval
(
_cacheInterval
);
LOG
(
debug
)
<<
" MQTT : "
<<
sensor
.
getMqtt
();
LOG
(
debug
)
<<
" Interval : "
<<
sensor
.
getInterval
();
LOG
(
debug
)
<<
" minValues: "
<<
sensor
.
getMinValues
();
LOG
(
debug
)
<<
" OID : "
<<
sensor
.
getOIDString
();
return
true
;
}
src/sensors/snmp/SNMPConfigurator.h
View file @
62974ab6
...
...
@@ -16,10 +16,12 @@
#include
<string>
#include
<vector>
#include
<map>
#include
<list>
#include
<boost/property_tree/ptree.hpp>
class
SNMPConfigurator
:
public
Configurator
{
typedef
std
::
list
<
SNMPConnection
>
connectionList_t
;
typedef
std
::
map
<
std
::
string
,
SNMPSensor
>
sensorMap_t
;
public:
...
...
@@ -35,7 +37,10 @@ public:
//Overwrite from Configurator
bool
reReadConfig
()
{
//TODO
for
(
auto
s
:
_sensors
)
{
s
->
stopPolling
();
}
_connections
.
clear
();
_templateSensors
.
clear
();
return
Configurator
::
reReadConfig
();
}
...
...
@@ -48,7 +53,8 @@ private:
*/
bool
readSensor
(
SNMPSensor
&
sensor
,
boost
::
property_tree
::
iptree
&
config
);
sensorMap_t
_templateSensors
;
connectionList_t
_connections
;
sensorMap_t
_templateSensors
;
};
extern
"C"
Configurator
*
create
()
{
...
...
src/sensors/snmp/SNMPConnection.cpp
View file @
62974ab6
...
...
@@ -7,13 +7,24 @@
#include
"SNMPConnection.h"
#include
<string>
SNMPConnection
::
SNMPConnection
()
{
// TODO Auto-generated constructor stub
_snmpCommunity
=
""
;
_oidPrefix
=
""
;
_host
=
""
;
_port
=
0
;
_snmpSession
.
community_len
=
0
;
_strand
=
NULL
;
}
SNMPConnection
::~
SNMPConnection
()
{
// TODO Auto-generated destructor stub
if
(
_snmpSession
.
community_len
)
{
free
(
_snmpSession
.
peername
);
free
(
_snmpSession
.
community
);
_snmpSession
.
community_len
=
0
;
}
}
void
SNMPConnection
::
initializeStrand
(
boost
::
asio
::
io_service
&
io
)
{
...
...
@@ -21,3 +32,62 @@ void SNMPConnection::initializeStrand(boost::asio::io_service& io) {
_strand
=
new
boost
::
asio
::
io_service
::
strand
(
io
);
}
}
void
SNMPConnection
::
init
()
{
snmp_sess_init
(
&
_snmpSession
);
_snmpSession
.
version
=
SNMP_VERSION_2c
;
_snmpSession
.
peername
=
strdup
(
_host
.
c_str
());
_snmpSession
.
community
=
(
u_char
*
)
strdup
(
_snmpCommunity
.
c_str
());
_snmpSession
.
community_len
=
_snmpCommunity
.
length
();
}
uint64_t
SNMPConnection
::
issueGet
(
oid
*
OID
,
size_t
OIDLen
)
{
struct
snmp_session
*
ss
;
struct
snmp_pdu
*
pdu
,
*
response
;
struct
variable_list
*
vp
;
int
status
;
uint64_t
ret
=
0
;
ss
=
snmp_open
(
&
_snmpSession
);
if
(
!
ss
)
{
throw
std
::
runtime_error
(
"Could not open SNMP Session!"
);
}
pdu
=
snmp_pdu_create
(
SNMP_MSG_GET
);
snmp_add_null_var
(
pdu
,
OID
,
OIDLen
);
status
=
snmp_synch_response
(
ss
,
pdu
,
&
response
);
if
(
status
==
STAT_SUCCESS
&&
response
->
errstat
==
SNMP_ERR_NOERROR
)
{
vp
=
response
->
variables
;
if
(
vp
)
{
if
(
vp
->
type
==
ASN_INTEGER
)
{
/* Trigger callback in SNMPPusher.cpp */
ret
=
*
vp
->
val
.
integer
;
}
else
if
(
vp
->
type
==
0x43
)
{
/* Timeticks: No idea why there is no definition for this in the libray */
/* Trigger callback in SNMPPusher.cpp */
ret
=
*
vp
->
val
.
integer
;
}
else
{
LOG
(
warning
)
<<
"Non-Integer and non-Timetick SNMP data received (type="
<<
std
::
to_string
((
int
)
vp
->
type
)
<<
"):"
;
char
buf
[
1024
];
while
(
vp
)
{
snprint_variable
(
buf
,
sizeof
(
buf
),
vp
->
name
,
vp
->
name_length
,
vp
);
LOG
(
warning
)
<<
ss
->
peername
<<
": "
<<
buf
;
vp
=
vp
->
next_variable
;
}
}
}
}
else
{
throw
std
::
runtime_error
(
"Request failed!"
);
}
if
(
response
)
{
snmp_free_pdu
(
response
);
}
snmp_close
(
ss
);
return
ret
;
}
src/sensors/snmp/SNMPConnection.h
View file @
62974ab6
...
...
@@ -12,6 +12,7 @@
#include
<net-snmp/net-snmp-config.h>
#include
<net-snmp/net-snmp-includes.h>
#include
<boost/asio.hpp>
class
SNMPConnection
{
...
...
@@ -19,13 +20,72 @@ public:
SNMPConnection
();
virtual
~
SNMPConnection
();
void
setSNMPCommunity
(
const
std
::
string
&
community
)
{
_snmpCommunity
=
community
;
}
const
std
::
string
&
getSNMPCommunity
()
const
{
return
_snmpCommunity
;
}
void
setOIDPrefix
(
const
std
::
string
&
oidPrefix
)
{
/* Ensure that the oidPrefix does not contain a trailing . */
_oidPrefix
=
oidPrefix
;
if
(
_oidPrefix
.
length
()
>
0
)
{
if
(
_oidPrefix
.
at
(
_oidPrefix
.
length
()
-
1
)
==
'.'
)
{
_oidPrefix
.
resize
(
_oidPrefix
.
size
()
-
1
);
}
}
}
const
std
::
string
&
getOIDPrefix
()
const
{
return
_oidPrefix
;
}
void
setHost
(
const
std
::
string
&
host
)
{
_host
=
host
;
}
const
std
::
string
&
getHost
()
const
{
return
_host
;
}
void
setPort
(
int
port
)
{
_port
=
port
;
}
int
getPort
()
const
{
return
_port
;
}
void
initializeStrand
(
boost
::
asio
::
io_service
&
io
);
boost
::
asio
::
io_service
::
strand
*
getStrand
()
const
{
return
_strand
;
}
/**
* Initializes the connection. Must be called once before the connection can be used
*/
void
init
();
/**
* Issues a get request to _host for the value specified by the OID.
*
* @param OID Pointer to the OID buffer which identifies the value to request
* @param OIDLen Lenght of the OID buffer
*
* @return The requested value
*/
uint64_t
issueGet
(
oid
*
OID
,
size_t
OIDLen
);
private:
std
::
string
_snmpCommunity
;
std
::
string
_oidPrefix
;
std
::
string
_host
;
int
_port
;
struct
snmp_session
_snmpSession
;
boost
::
asio
::
io_service
::
strand
*
_strand
;
boost
::
log
::
sources
::
severity_logger
<
boost
::
log
::
trivial
::
severity_level
>
lg
;
};
...
...
src/sensors/snmp/SNMPSensor.cpp
View file @
62974ab6
...
...
@@ -10,27 +10,30 @@
SNMPSensor
::
SNMPSensor
(
const
std
::
string
&
name
)
:
Sensor
(
name
)
{
// TODO Auto-generated constructor stub
memset
(
_oid
,
0x0
,
sizeof
(
oid
)
*
MAX_OID_LEN
);
_oidLen
=
0
;
_connection
=
NULL
;
}
SNMPSensor
::~
SNMPSensor
()
{
//
TODO Auto-generated destructor stub
//
Nothing to do
}
void
SNMPSensor
::
read
()
{
reading_t
reading
;
char
buf
[
1024
];
reading
.
timestamp
=
getTimestamp
();
//TODO
try
{
reading
.
value
=
_connection
->
issueGet
(
_oid
,
_oidLen
);
storeReading
(
reading
);
_latestValue
.
value
=
reading
.
value
;
_latestValue
.
timestamp
=
reading
.
timestamp
;
#ifdef DEBUG
LOG
(
debug
)
<<
_name
<<
":
\"
"
<<
reading
.
value
<<
"
\"
"
;
#endif
}
catch
(
const
std
::
exception
&
e
)
{
LOG
(
error
)
<<
_name
<<
" could not read value: "
<<
e
.
what
();
}
storeReading
(
reading
);
}
void
SNMPSensor
::
readAsync
()
{
...
...
@@ -59,8 +62,6 @@ void SNMPSensor::startPolling() {
return
;
}
//TODO
if
(
_connection
)
{
_keepRunning
=
1
;
_timer
->
async_wait
(
_connection
->
getStrand
()
->
wrap
(
std
::
bind
(
&
SNMPSensor
::
readAsync
,
this
)));
...
...
@@ -77,8 +78,5 @@ void SNMPSensor::stopPolling() {
_timer
->
cancel
();
//wait until read() finished before closing _file
_timer
->
wait
();
//TODO
LOG
(
info
)
<<
"Sensor "
<<
_name
<<
" stopped."
;
}
src/sensors/snmp/SNMPSensor.h
View file @
62974ab6
...
...
@@ -9,6 +9,7 @@
#define SNMPSENSOR_H_
#include
"../../Sensor.h"
#include
"SNMPConnection.h"
#include
<net-snmp/net-snmp-config.h>
#include
<net-snmp/net-snmp-includes.h>
...
...
@@ -19,6 +20,37 @@ public:
SNMPSensor
(
const
std
::
string
&
name
);
virtual
~
SNMPSensor
();
void
setOID
(
std
::
string
oid
)
{
size_t
newoidnamelen
=
MAX_OID_LEN
;
if
(
read_objid
(
oid
.
c_str
(),
_oid
,
&
newoidnamelen
))
{
_oidLen
=
newoidnamelen
;
}
else
{
LOG
(
error
)
<<
_name
<<
": Cannot convert OID string: "
<<
oid
;
}
}
const
oid
*
getOID
()
const
{
return
_oid
;
}
std
::
string
getOIDString
()
{
char
buf
[
255
];
int
len
=
snprint_objid
(
buf
,
255
,
_oid
,
_oidLen
);
if
(
len
==
-
1
)
{
LOG
(
error
)
<<
_name
<<
": getOIDString buffer not large enough!"
;
return
std
::
string
(
""
);
}
return
std
::
string
(
buf
,
len
);
}
void
setConnection
(
SNMPConnection
*
connection
)
{
_connection
=
connection
;
}
SNMPConnection
*
getConnection
()
const
{
return
_connection
;
}
void
init
(
boost
::
asio
::
io_service
&
io
);
void
read
();
...
...
@@ -30,8 +62,8 @@ public:
void
stopPolling
();
private:
oid
_oid
Name
[
MAX_OID_LEN
];
size_t
_oid
Name
Len
;
oid
_oid
[
MAX_OID_LEN
];
size_t
_oidLen
;
SNMPConnection
*
_connection
;
};
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment